[noi34]palindrome
分割实际上就是不断地从两端取出一样的一段,并对剩下的串进行分割。下面我们来证明一下每一次贪心取出最短一段的正确性:
考虑两种分割方式,分别表示成S=A+B+A和S=C+D+C,其中A就是最短的一段,那么当2|A|<|C|,显然就有C=A+E+A,那么就可以用三次划分来完成C,而当|A|<|C|<2|A|,即A在C中重叠了,那么最短的前缀一定不是A,而是重叠部分(重叠部分既是A的前缀又是A的后缀)。
那么这个贪心就成立了,用hash暴力判断即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 1000000007 4 #define ll long long 5 #define N 1000001 6 int t,l; 7 ll sum[N],mi[N]; 8 char s[N]; 9 ll calc(int l,int r){ 10 return ((sum[r]-sum[l-1]*mi[r-l+1])%mod+mod)%mod; 11 } 12 int work(int l,int r){ 13 if (l>r)return 0; 14 int mid=(l+r+1>>1),k=l; 15 while ((k<mid)&&(calc(l,k)!=calc(l+r-k,r)))k++; 16 if (k==mid)return 1; 17 return work(k+1,l+r-k-1)+2; 18 } 19 int main(){ 20 mi[0]=1; 21 for(int i=1;i<N;i++)mi[i]=(mi[i-1]*29)%mod; 22 scanf("%d",&t); 23 while (t--){ 24 scanf("%s",s); 25 l=strlen(s); 26 sum[0]=s[0]-'a'+1; 27 for(int i=1;i<l;i++)sum[i]=(sum[i-1]*29+s[i]-'a'+1)%mod; 28 printf("%d\n",work(0,l-1)); 29 } 30 }