Codeforces Round #616 (Div. 2) (A-D)

Codeforces Round #616 (Div. 2)

A
最开始写挂了,打算从后往前截断到第一个奇数,再从前往后截断到数码和为偶数,不过并通过不了test2。

后来发现如果末尾一定要是奇数,那么前面一定还得有一个奇数才能使得数码和为偶数。所以只需要对串搜索找两个奇数就好了。
还是写挂了一发,原因有可能是因为在main函数中开了char ans[2]但是输出的时候用了%s,而局部变量的初始化并不一定满足能够在ans + 2的位置成功截断。

B
对增区间而言,其中每一个元素都要满足 a [ i ] > = i a[i] >= i a[i]>=i (从0开始计数)。一旦某个元素不满足,那么这段区间无论如何都不可能都不能成为一个严格的增区间,进而比这个在元素之后的所有位置也都不可能成为峰点;类似地可以推出减区间的情况。用两个flag数组记录前缀后缀的情况,最后枚举所有可能的峰点位置,用flag1 & flag2的值判断是否可行即可。

C
大体地考虑一下所有情况之间的共同点可以发现,那些可行区间的长度并没有发生变化,只是在大区间[1,n]上左右平移,所以我们只需要具体分析我们能取到的元素到底在什么位置。
k = m i n ( m − 1 , k ) , u = m − 1 − k k= min(m - 1, k), u = m - 1 -k k=min(m1,k),u=m1k,我们可以精控而获得的起始序列(从1开始计数)为[1 + i, n - k + i], i = 0, 1, ..k,之后因为剩下u个人可以不受控制地随意选择,那么我们可能获得的最终序列又为[1 + i + j, n - k - u + i + j], j = 0, 1, ..., u,而面对这个最终序列的"我"是有智力的,所以会选择两端中较大的一个。注意到题目给定的范围暗示着二重循环,所以可得最终计算式:

k = min(k, m - 1); int u = m - 1 - k, d = n - k - u - 1;
int ans = 0;
for(int i = 0; i <= k; i++){
    int res = 0x3f3f3f3f;
    //在大的里面找最坏的情况
    for(int j = 0; j <= u; j++) res = min(res, max(a[i + j], a[i + j + d]));
    //最大化最小值
    ans = max(ans, res);
}

补题

D
昨晚想了一阵子但是并没有什么想法,加上有点困和这道题就过了二十来个人…所以我打完三题就溜了…

正确的做法是从元素种数入手,寻找母串一定拥有不可划分的相似串的充要条件。

  • 当只有一种元素时,仅当这种元素只有1个时不可划分,其余均无不可划分串。
  • 当拥有两种元素时,仅当两端元素不同时拥有不可划分串。考虑如下情形s: a-b,那么就可以构造不可划分串t: b-a,其中-是相同的子串,那么无论如何对s、t进行划分都不可能使得每一部分都互相相似;而如果两端元素相同,那么怎样构造都不能构造出一个不可划分串。
  • 当拥有三种元素及以上时,一定可以构造出一个不可划分串。不妨只需要考虑两端元素相同的情况(不然由上述情况推出一定有不可划分串),用字母和-表示s: a-b-c-a,那么构造t: c-a-a-b就获得了一个不可划分串。

知道了这些充要条件后判断就变的很容易了,当查询区间内元素种数的时候直接用26个字母的前缀和进行O(26)的查询即可。

总体来说这道题不算特别难的算法题,但是比较考验分析、构造的思维能力…
以及一定的场上打题策略

代码

const int maxn = 2e5 + 10;
char s[maxn];

//cnt[i][j]表示位置i及其之前的出现字符 j+'a' 的个数
int cnt[maxn][26];

int main(){
//    Fast;
    scanf("%s", s + 1); int n = (itn)strlen(s + 1);
    for(int i = 1; i <= n; i++){
        char c = s[i];
        for(int j = 0 ; j < 26; j++){
            if(j == c - 'a') cnt[i][j] = cnt[i - 1][j] + 1;
            else cnt[i][j] = cnt[i - 1][j];
        }
    }
    int q; scanf("%d", &q);
    for(int i = 0; i < q; i++){
        int l, r, flag = 0; scanf("%d%d", &l, &r);
        if(l == r) flag = 1;
        else if(s[l] != s[r]) flag = 1;
        else{
            int temp = 0;
            for(int i = 0; i < 26; i++) if(cnt[r][i] - cnt[l - 1][i] > 0) temp++;
            if(temp >= 3) flag = 1;
        }
        if(flag) puts("Yes");
        else puts("No");
    }
    return 0;
}

你可能感兴趣的:(ACM)