Codeforces Round 856 (Div. 2) (VP)

文章介绍了几个编程问题的解决方案,包括判断回文串、数组操作以及求解序列子串得分的最大长度。针对每个问题,提出了不同的算法思路,如通过比较子串确定字符串是否为回文,对数组元素执行不超过2n次的加一操作以满足特定条件,以及使用二分查找优化求解序列子串得分问题。
摘要由CSDN通过智能技术生成

A. Prefix and Suffix Array

题意:给定一个字符串的长度n,并按任意顺序给出n * 2 - 2个前缀和后缀子串,判断该串是不是pralindrome字符串

思路:找到两个n-1的字符串,然后判断出两个子串哪个是前缀,哪个是后缀,将子串拼接成原本的字符串s,再判断是不是回文串。

// Created on ?.

#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
typedef long long int ll;

bool if_parlindrome(string& s){
    int l = 0,r = s.size() -1;
    while (l < r){
        if (s[l] != s[r]) return false;
        l += 1, r -= 1;
    }
    return true;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int N;
    cin >> N;
    while (N--){
        int n;
        cin >> n;
        int t = 2 * n - 2;
        string s1 = "",s2 = "", tmp;
        while (t--){
            cin >> tmp;
            if (tmp.size() != n - 1) continue;
            s2 = s1, s1 = tmp;
        }
        //cout << s1 << " " << s2 << endl;
        if (s1.substr(1, s1.size() - 1) == s2.substr(0, s2.size() - 1)) s1 += s2[n - 2];
        else s1 = s2[0] + s1;
        //cout << s1 << endl;
        cout << (if_parlindrome(s1) ? "YES" : "NO") << endl;
    }
}

总结:一开始在区分前后缀子串时用的方法是看s1的子串的第二个字符是不是跟s2的第一个字符相等来进行区分,测试示例可以跑过去,但是后续会出错,后来改变了判定字符串的方式才跑过去。

B. Not Dividing

题意:给定一个数组,可以对这个数组的任意元素执行+1操作,且操作总数不超过2n,n为数组长度,且操作后的数组需后面的数MOD前面的数不为0。

思路:假设a与b相邻,b在a后面,那么若要b % a != 0,如果a为1,则b无论如何修改都不行,所以在扫描数组的时候先将所有为1的数值加1改为2。其次如果b<a,那么b % a 必然不为0,所以秩序要将数组从左往右遍历一次,将不满足条件的b往上累加直到满足条件即可。

// Created on ?.

#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
typedef long long int ll;

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int N;
    cin >> N;
    while (N--){
        int n;
        cin >> n;
        vi a(n);
        for (int i = 0; i < n; ++i){cin >> a[i]; if (a[i] == 1) a[i] += 1;}
        for (int i = 1; i < n; ++i){
            while (a[i] % a[i - 1] == 0) {a[i] += 1; } 
        }
        for (int i = 0; i < n; ++i){cout << a[i] << " \n"[i + 1 == n];}
    }
}

总结:一开始考虑的是如果相邻的两个数存在不同的质因子,那么就必然不能整除,于是打算在输入数据时对每个数进行质因子扫描,但是想了想好像有点麻烦,需要写很多规则出来,就直接brute force了,没想到速度还挺快。

C. Scoring Subsequences

题意:

给定一个长度为n的数组a,规定a[i]的score为max(a[i] * a[i - 1] * ..... a[j]/ 1 * 2 *...(i - j + 1)),

0 <=j <= i <= n,对于每个a[i]的score m,找到a[0] ~ a[i]中score为m的最长子串的长度。

思路:score的确定是以i为边界,不断的向左移动,找一个左边界,这个最大的左边界就是最大子串的长度。因为score的公式是a[i]的元素不断的往左乘,然后除以元素数的阶乘,也就是说在往左寻找的过程中,只要元素的数值大于该位置阶乘要乘的数字的值,那么这个位置就可以保留下来继续向左延伸,一直到a[j] < k (2 <= k <= i + 2),先上暴力破解的代码。

// Created on ?.

#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
typedef long long int ll;


int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int N;
    cin >> N;
    while (N--){
        int n;
        cin >> n;   
        vi a(n + 1, 0);
        for (int i = 1; i <= n; ++i){
            cin >> a[i];
            int k = 2, j = i - 1;
            while (j > 0 && k <= a[j]){
                j -= 1;
                k += 1;
            }
            cout << i - j << " \n"[i == n]; 
        }
    }
}// 1 1 2 2 3 3 4 4

不出意外,Brute force果然超时,考虑到输入数据为10的五次方级别,这里的查找方式要更改一下,于是想到了二分查找。

对于二分查找, 可以将i-1在的位置设为左边界,然后0为右边界,每次可以求出区间的中间值m。这里设一个dis = i - m + 1,这个值就是i向左延申的左边界,用dis去和a[m]做比较,如果dis <= a[m],那么可以继续向左查找。

上代码

// Created on ?.

#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
typedef long long int ll;


int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int N;
    cin >> N;
    while (N--){
        int n;
        cin >> n;   
        vi a(n + 1, 0);
        for (int i = 1; i <= n; ++i){
            cin >> a[i];
            int l = i - 1, r = 1;
            while (r <= l){
                int m = (l + r) >> 1, dis = i - m + 1;
                if (a[m] < dis){r = m + 1;}
                else if (a[m] >= dis){l = m - 1;}
            }
            cout << i - l << " \n"[i == n]; 
        }
    }
}// 1 1 2 2 3 3 4 4

总结:这个题的难点关键在于理解题意,因为题目一开始好像说的不清楚,或者是我英文水平低,没理解题意。理解了题意以后还要知道最大score是如何计算出来的,因为一开始写的时候是用了动态规划,让f[i] = max (f[i - 1] * idx! , a[i]),这样得到的并不是最大score....之后确定了如何得到最大score以后就要在查找上面下功夫了,这个题的查找不是很难,关键在于下标的确定。

D. Counting Factorizations

一开始以为是简单的爬楼梯问题,但是怎么写都感觉有点问题,然后发现p是一个递增序列,暂时有点懵,先跳过了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值