[POI2010]Beads

题目大意:
  给定一个长度为$n(nleq200000)$的串$S_{1sim 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
",ans,v.size());
48     for(register unsigned i=0;i<v.size();i++) {
49         printf("%d%c",v[i]," 
"[i==v.size()-1]);
50     }
51     return 0;
52 }
原文地址:https://www.cnblogs.com/skylee03/p/8557055.html