前缀和:Codeforces Round #764 (Div. 3) D. Palindromes Coloring

Codeforces Round #764 (Div. 3) D. Palindromes Coloring 

 

 

 

 

 

     题目的大意就是给你一串字符串,都是由a b c三个字符所构成,给出m次询问,每次循环给你一个l 和 r,分别表示在字符串左端点和右端点的下标+1,求这个子串最少变动几次能变成没有回文的子串,这里的回文指的是两个以上的回文,如aa aba cabac ,变动的意思是 每个字母可以换成 a b c中的任何一个。

    分析一下:要想让一个字符串没有回文,那么 S[i-1]!=S[i]!=S[i+1],所以连续的三个只能是abc acb ....abc构成的全排列,有六种,推广到更长的子串,没有回文:只能是按照abc的全排列的循环,如abcabcabc...,所以我们创建一个二维数组,因为abc的全排列有六种,所以行就是6,列就是字符串s的长度,里面的元素代表全排列循环的字符串和S的每一个字符是不是一样的,不一样就是1,一样就是0,因为不一样要花费1次去改变,可以称之为:差异前缀和。因为是全排列循环的字符串,所以子串的起始点放在哪里算出来的最优解都一样,所以可以这么做,不用考虑循环字符串abc abc abc 和S:acbca中,我们把S的起点放在不同的位置算出来的值不一样,确实不一样,但是放在第一个位置是一种,放在第二个位置就是循环字符串bcabcabca的情况了,所以我们统一放在第一个,最后用前缀和一样二维数组的每一层,每次询问其实就是算sum[r]-sum[l-1],我们用一个循环一次遍历6层,找到最优的前缀和,即可。for(int i=1->6)答案求解公式:ans=min(sum[i][r]-sum[i][l-1]);全排列利用next_permutation函数,do while 函数.

  这里有两种方法

一、两种方法其实差别不大,原理是一样的,具体写法有些出入。

  

 1 #include <algorithm>
 2 #include <iostream>
 3 #include<cmath>
 4 using namespace std;
 5 const int maxn = 2 * 1e5 + 5;
 6 int sum[6][maxn];//abc的全排列有6种 差异前缀和数组
 7 string s;
 8 string abc;
 9 int main()
10 {
11     int n, m;
12     cin >> n >> m >> s;
13     abc = "abc";//初始化成abc 等下利用全排列
14     int floor=0;
15     do 
16     {
17         int num = 0; //num一定要在每次do中重新定义一次为0 不然会错!
18         for (int i = 0;i<n;++i)
19         {
20             sum[floor][i+1] =(abc[num]!=s[i]);//用bool值记录 差异前缀和
21             num++;
22             if (num == 3)
23                 num = 0;
24         }
25         floor++;
26     } while (next_permutation(abc.begin(), abc.end()));
27     for(int i=0;i<6;++i)
28         for (int j = 1; j <= n; ++j)
29         {
30             sum[i][j] += sum[i][j - 1];
31         }
32     while (m--)
33     {
34         int l, r;
35         cin >> l >> r;
36         int ans = 99999;
37         for (int i = 0; i < 6; ++i)
38             ans =min(sum[i][r] - sum[i][l - 1],ans);
39         cout << ans << endl;
40     }
41     return 0;
42 }

二、这种方法用的是结构体,并且答案先算着到最后一起输出,在全排列每一层的算出来的sum数组就直接算出来需要的sum[r]-sum[l-1]如果更优,就更新l r对应的ans

 1 #include <algorithm>
 2 #include <iostream>
 3 using namespace std;
 4 const int maxn = 2e5 + 7;
 5 #define ll long long
 6 int n, m, k, tot;
 7 struct _ {
 8     int l, r, ans;
 9 }q[maxn];
10 int rd() {
11     int s = 0, f = 1; char c = getchar();
12     while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
13     while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();}
14     return s * f;
15 }
16 char s[maxn];
17 char ch[3] = {'a','b','c'};
18 int a[3] = {0, 1, 2}, cnt[maxn];
19 int main() {
20     n = rd(); m = rd();
21     scanf("%s", s + 1);
22     for (int i = 1; i <= m; i++) {
23         q[i].l = rd(); q[i].r = rd();
24         q[i].ans = maxn;
25     }
26     do {
27         for (int i = 1; i <= n; i++) {
28             cnt[i] =  (s[i] != ch[a[i%3]]);
29             
30         }
31         for (int i = 1; i <= n; i++) cnt[i] += cnt[i-1];
32         for (int i = 1; i <= m; i++) 
33             q[i].ans = min(q[i].ans, cnt[q[i].r]-cnt[q[i].l-1]);
34     }while (next_permutation(a,a+3));
35     for (int i = 1; i <= m; i++) printf("%d\n", q[i].ans);
36     return 0;
37 }

 

posted @ 2022-04-14 09:38  朱朱成  阅读(41)  评论(0编辑  收藏  举报