题目概述
有一个仅有abc三种字母组成的字符串。定义一个字符串是美丽的,当且仅当它不含有长度大于等于2的回文串。现在有若干询问,每次询问一个$[l,r]$,需要回答将此区间的字符串变成美丽的的最小修改代价。
分析与解
关键一点是抓住奇回文只需要规避掉aba形,偶回文只需要规避掉aa形,就可以灭掉所有的回文串了。接着我们可以进一步发现,由于上面的两种限制,整个字符串必须是循环的形式:
所以用输入的总字符串来匹配上面六种合法的情况,记一个修改代价的前缀和。面对每个$[l,r]$只需要看6种前缀和作差哪个最小即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| #include <bits/stdc++.h> using namespace std; #define min(a,b) (a)<(b) ? (a) : (b) #define max(a,b) (a)>(b) ? (a) : (b) typedef long long LL; int mread() { int ret=0,f=1; char c=getchar(); while(c<'0' || c>'9') { if(c=='-')f=-1; c=getchar(); } do { ret=ret*10+c-'0'; c=getchar(); } while('0'<=c && c<='9'); return ret*f; } #define MAXN 200100 int n,m; char s[MAXN]; int sum[7][MAXN]; int main() { int l,r; n=mread(),m=mread(); scanf("%s",s+1); for(int j=1; j<=n; j++) { sum[1][j]=sum[1][j-1]; sum[2][j]=sum[2][j-1]; sum[3][j]=sum[3][j-1]; sum[4][j]=sum[4][j-1]; sum[5][j]=sum[5][j-1]; sum[6][j]=sum[6][j-1]; if(s[j]=='a') { if(j%3==1) { sum[3][j]++; sum[4][j]++; sum[5][j]++; sum[6][j]++; } else if(j%3==2) { sum[1][j]++; sum[2][j]++; sum[4][j]++; sum[6][j]++; } else { sum[1][j]++; sum[2][j]++; sum[3][j]++; sum[5][j]++; } } else if(s[j]=='b') { if(j%3==1) { sum[1][j]++; sum[2][j]++; sum[5][j]++; sum[6][j]++; } else if(j%3==2) { sum[2][j]++; sum[3][j]++; sum[4][j]++; sum[5][j]++; } else { sum[1][j]++; sum[3][j]++; sum[4][j]++; sum[6][j]++; } } else if(s[j]=='c') { if(j%3==1) { sum[1][j]++; sum[2][j]++; sum[3][j]++; sum[4][j]++; } else if(j%3==2) { sum[1][j]++; sum[3][j]++; sum[5][j]++; sum[6][j]++; } else { sum[2][j]++; sum[4][j]++; sum[5][j]++; sum[6][j]++; } } } int mmin; while(m--) { l=mread(),r=mread(); mmin=0x3f3f3f3f; for(int i=1; i<=6; i++) mmin=min(mmin,sum[i][r]-sum[i][l-1]); printf("%d\n",mmin); } return 0; }
|