CF1555D Say No to Palindromes(線段樹)
阿新 • • 發佈:2021-08-03
CF1555D Say No to Palindromes
看題目問法是線段樹來做的。
仔細分一下發現,若有一個沒有迴文子串的串 \(s\),對於任意 \(i\),一定有 \(s_i\neq s_{i-1}\neq s_{i+1}\)。也就是說嗎,這三個字元分別對應 a,b,c
。也就是說, \(s\) 的形式只有一下 \(6\) 種:
abcabc...
bcabca...
cabcab...
acbacb...
cbacba...
bacbac...
對於線段樹一個區間,我們維護 \(s_{l,r}\) 對應 \(6\) 種可能修改後的形式修改的字元數量即可。
明顯我們可以通過這 \(6\)
pushup
。
其他操作和基礎線段樹差不多。
為了寫程式碼方便,你需要對著 \(6\) 種形式合理編號。
//Don't act like a loser. //This code is written by huayucaiji //You can only use the code for studying or finding mistakes //Or,you'll be punished by Sakyamuni!!! #include<bits/stdc++.h> using namespace std; int read() { char ch=getchar(); while(ch<'a'||ch>'c') { ch=getchar(); } return (ch-'a'+1)%3; } const int MAXN=2e5+10; int n,m; int a[MAXN]; struct segment { int val[2][3],len; }s[MAXN<<2]; segment pushup(segment lft,segment rgt) { segment ret; ret.len=lft.len+rgt.len; for(int j=0;j<2;j++) { for(int i=0;i<3;i++) { ret.val[j][i]=lft.val[j][i]+rgt.val[j][(i+lft.len%3)%3]; } } return ret; } void build(int l,int r,int p) { if(l==r) { for(int j=0;j<2;j++) { for(int i=0;i<3;i++) { s[p].val[j][i]=1; } } if(a[l]==1) { s[p].val[0][0]=s[p].val[1][0]=0; } if(a[l]==2) { s[p].val[0][1]=s[p].val[1][2]=0; } if(a[l]==0) { s[p].val[0][2]=s[p].val[1][1]=0; } s[p].len=1; return ; } int mid=(l+r)>>1; build(l,mid,p<<1); build(mid+1,r,p<<1|1); s[p]=pushup(s[p<<1],s[p<<1|1]); } segment query(int l,int r,int p,int x,int y) { if(r<x||y<l) { return s[0]; } if(x<=l&&r<=y) { return s[p]; } int mid=(l+r)>>1; return pushup(query(l,mid,p<<1,x,y),query(mid+1,r,p<<1|1,x,y)); } signed main() { cin>>n>>m; for(int i=1;i<=n;i++) { a[i]=read(); } build(1,n,1); while(m--) { int l,r; scanf("%d%d",&l,&r); segment tmp=query(1,n,1,l,r); int ans=1e9; for(int j=0;j<2;j++) { for(int i=0;i<3;i++) { ans=min(ans,tmp.val[j][i]); } } printf("%d\n",ans); } return 0; }
看了一眼官方題解後發現這個題是傻題。
希望大家學習一下這個思路就行,以官方題解的解法為主。