[POI2010]Beads
题目大意:
给定一个长度为$n(n\leq200000)$的串$S_{1\sim n}$,选择一个$l$,从$S_1$开始,将$S$分为连续的若干段,使得每一段长度为$l$。令$k$为分出来不同的子串个数(翻转后相同算作相同),求最大的$k$,以及有哪些$l$对应的答案为$k$。
思路:
枚举长度,求正反两个哈希去重。
1 #include<set> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 typedef unsigned long long uint64; 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=200002,BASE=2333; 14 int a[N]; 15 uint64 pow[N],h1[N],h2[N]; 16 std::set<uint64> set; 17 std::vector<int> v; 18 inline uint64 hash1(const int &l,const int &r) { 19 return h1[r]-h1[l-1]*pow[r-l+1]; 20 } 21 inline uint64 hash2(const int &l,const int &r) { 22 return h2[l]-h2[r+1]*pow[r-l+1]; 23 } 24 int main() { 25 const int n=getint(); 26 for(register int i=1;i<=n;i++) a[i]=getint(); 27 for(register int i=1;i<=n;i++) h1[i]=h1[i-1]*BASE+a[i]; 28 for(register int i=n;i>=0;i--) h2[i]=h2[i+1]*BASE+a[i]; 29 for(register int i=pow[0]=1;i<=n;i++) pow[i]=pow[i-1]*BASE; 30 int ans=0; 31 for(register int i=1;ans*i<=n;i++) { 32 set.clear(); 33 int tmp=0; 34 for(register int j=1;i+j-1<=n;j+=i) { 35 const int h1=hash1(j,j+i-1),h2=hash2(j,j+i-1); 36 if(!set.count(h1)||!set.count(h2)) { 37 set.insert(h1),set.insert(h2); 38 tmp++; 39 } 40 } 41 if(tmp>ans) { 42 ans=tmp; 43 v.clear(); 44 } 45 if(tmp==ans) v.push_back(i); 46 } 47 printf("%d %lu\n",ans,v.size()); 48 for(register unsigned i=0;i<v.size();i++) { 49 printf("%d%c",v[i]," \n"[i==v.size()-1]); 50 } 51 return 0; 52 }