前缀和: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 }