T1 Power Strings poj 2406
题目大意:
求每个字符串的最短循环节的循环次数
思路:
哈希用kmp做
直接判断一下n-nxt[n]是否是n的约数
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 100100100 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 int n,nxt[MAXN]; 21 char a[MAXN]; 22 int main() 23 { 24 while(scanf("%s",a+1)) 25 { 26 if(a[1]=='.') break; 27 n=strlen(a+1); 28 for(int i=1,j=0;i<n;i++) 29 { 30 while(a[i+1]!=a[j+1]&&j) j=nxt[j]; 31 if(a[i+1]==a[j+1]) j++; 32 nxt[i+1]=j; 33 } 34 if(n%(n-nxt[n])==0) printf("%d ",n/(n-nxt[n])); 35 else puts("1"); 36 } 37 }
T2 Seek the name ... poj 2752
题目大意:
求每个字符串的所有border
思路:
用nxt[n]一直往前跳nxt就行了
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 400100 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 int n,nxt[MAXN]; 21 char a[MAXN]; 22 void work(int x) {if(!x)return ;work(nxt[x]);printf("%d ",x);} 23 int main() 24 { 25 while(scanf("%s",a+1)!=EOF) 26 { 27 n=strlen(a+1); 28 for(int i=1,j=0;i<n;i++) 29 { 30 while(a[i+1]!=a[j+1]&&j) j=nxt[j]; 31 if(a[i+1]==a[j+1]) j++; 32 nxt[i+1]=j; 33 } 34 work(n);puts(""); 35 } 36 }
T3 friends bzoj 3916
题目大意:
字符串s复制一遍后加入一个字符x得到字符串t
已知t 求s的个数
思路:
枚举插入的位置 字符串哈希判断
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #define inf 2139062143 11 #define ll long long 12 #define MAXN 2000100 13 const int MOD=1e9+7; 14 using namespace std; 15 inline int read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 19 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 map <int,int> vis; 23 int n,ans,t; 24 ll hsh[MAXN],p[MAXN]; 25 char ch[MAXN]; 26 ll Minus(ll a,ll b) {return (a-b)%MOD>0?(a-b)%MOD:(a-b)%MOD+MOD;} 27 int main() 28 { 29 n=read(),p[0]=1; 30 scanf("%s",ch+1); 31 if(!(n&1)) {puts("NOT POSSIBLE");return 0;} 32 for(int i=1;i<=n;i++) p[i]=(p[i-1]*137)%MOD,hsh[i]=(ch[i]-'A'+1+hsh[i-1]*137%MOD)%MOD; 33 for(int i=1,x,y;i<=n;i++) 34 { 35 if(i<=n/2+1) x=(hsh[i-1]*p[n/2-i+1]%MOD+Minus(hsh[n/2+1],hsh[i]*p[n/2+1-i]))%MOD,y=Minus(hsh[n],hsh[n/2+1]*p[n/2]); 36 else x=hsh[n/2],y=(Minus(hsh[i-1],hsh[n/2]*p[i-n/2-1])*p[n-i]%MOD+Minus(hsh[n],hsh[i]*p[n-i]))%MOD; 37 if(x==y&&!vis[x]) ans++,t=i,vis[x]=1; 38 } 39 if(!ans) puts("NOT POSSIBLE"); 40 else if(ans>1) puts("NOT UNIQUE"); 41 else if(t>=n/2+1) for(int i=1;i<=n/2;i++) printf("%c",ch[i]); 42 else for(int i=n/2+2;i<=n;i++) printf("%c",ch[i]); 43 }
T4 A Horrible Poem bzoj 2795
题目大意:
q次询问 每次询问字符串的一段子串的最短循环节
思路:
很容易想到 q sqrt(n) 枚举每段长度的所有约数 O1 判断
但是感觉太捞了
于是可以分解质因数 用线筛求出每个数最小的质因数
不断枚举质因数 用长度判断
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #define inf 2139062143 11 #define ll long long 12 #define MAXN 500100 13 const int MOD=1e9+7; 14 using namespace std; 15 inline int read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 19 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 ll Minus(ll a,ll b) {return (a-b)%MOD>0?(a-b)%MOD:(a-b)%MOD+MOD;} 23 int n,T,ntp[MAXN],p[MAXN],cnt; 24 char ch[MAXN]; 25 ll hsh[MAXN],pw[MAXN]; 26 void mem() 27 { 28 for(int i=2;i<MAXN;i++) 29 { 30 if(!ntp[i]) ntp[i]=i,p[++cnt]=i; 31 for(int j=1;p[j]*i<MAXN;j++) 32 { 33 ntp[p[j]*i]=p[j]; 34 if(i%p[j]==0) break; 35 } 36 } 37 } 38 int main() 39 { 40 n=read(),pw[0]=1;int a,b,len; 41 scanf("%s",ch+1); 42 for(int i=1;i<=n;i++) pw[i]=(pw[i-1]*137)%MOD,hsh[i]=(ch[i]-'a'+1+hsh[i-1]*137%MOD)%MOD; 43 T=read();mem(); 44 while(T--) 45 { 46 a=read(),b=read(),len=b-a+1; 47 for(int i=len,c;i>1;) 48 { 49 c=ntp[i]; 50 while(len%c==0&&Minus(hsh[b-len/c],hsh[a-1]*pw[b-len/c-a+1])==Minus(hsh[b],hsh[a+len/c-1]*pw[b-a-len/c+1])) len/=c; 51 while(i%c==0) i/=c; 52 } 53 printf("%d ",len); 54 } 55 }
T5 Beads bzoj 2081
题目大意:
求一些长度 使这些紧挨着的长度的子串有多少个不同的(前后翻转算一个)
思路:
暴力枚举长度 由调和级数可得总复杂度为 nlogn
然后使用set 和哈希求出多少个不同的子串即可
卡1e9+7 但没卡自然溢出是什么鬼
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<set> 10 #define inf 2139062143 11 #define ll long long 12 #define MAXN 200100 13 const int MOD=98754321; 14 using namespace std; 15 inline int read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 19 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 set <int> s; 23 int n,ans,ar[MAXN],cnt,g[MAXN],hsh[MAXN],HSH[MAXN],pw[MAXN]; 24 char ch[MAXN]; 25 void calc(int x) 26 { 27 s.clear(); 28 for(int i=1,a,b;i+x-1<=n;i+=x) 29 { 30 a=hsh[i+x-1]-hsh[i-1]*pw[x],b=HSH[i]-HSH[i+x]*pw[x]; 31 s.insert(min(a,b)); 32 } 33 if(s.size()==ans) ar[++cnt]=x; 34 if(s.size()>ans) ans=s.size(),ar[cnt=1]=x; 35 } 36 int main() 37 { 38 n=read(); 39 for(int i=pw[0]=1;i<=n;i++) g[i]=read(),pw[i]=pw[i-1]*19260817,hsh[i]=g[i]+hsh[i-1]*19260817; 40 for(int i=n;i;i--) HSH[i]=g[i]+HSH[i+1]*19260817; 41 for(int i=1;i<=n;i++) calc(i); 42 printf("%d %d %d",ans,cnt,ar[1]); 43 for(int i=2;i<=cnt;i++) printf(" %d",ar[i]); 44 }
T6 Antisymmetry bzoj 2084
题目大意:
对一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串
现在给出一个长度为N的01字符串,求它有多少个子串是反对称的
思路:
枚举每个中心
然后二分长度 哈希判断
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<set> 10 #define inf 2139062143 11 #define ll long long 12 #define MAXN 500100 13 const int MOD=1e9+7; 14 const int bas=2333; 15 using namespace std; 16 inline int read() 17 { 18 int x=0,f=1;char ch=getchar(); 19 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 20 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 21 return x*f; 22 } 23 int n; 24 ll hsh[MAXN],HSH[MAXN],pw[MAXN],ok[MAXN],ans; 25 char ch[MAXN]; 26 int check(int pos,int x) 27 { 28 return ((hsh[pos+x]-hsh[pos-x]*pw[2*x]%MOD+MOD)%MOD+(HSH[pos-x+1]-HSH[pos+x+1]*pw[2*x]%MOD+MOD)%MOD)%MOD==ok[2*x]; 29 } 30 int main() 31 { 32 n=read();scanf("%s",ch+1); 33 for(int i=pw[0]=1;i<=n;i++) pw[i]=pw[i-1]*bas%MOD,hsh[i]=(ch[i]-'0'+hsh[i-1]*bas%MOD)%MOD,ok[i]=(1+ok[i-1]*bas%MOD)%MOD; 34 for(int i=n;i;i--) HSH[i]=(ch[i]-'0'+HSH[i+1]*bas%MOD)%MOD; 35 for(int i=1,l,r,mid,res;i<n;i++) 36 { 37 res=l=0,r=min(i,n-i); 38 while(l<=r) 39 { 40 mid=(l+r)>>1; 41 if(check(i,mid)) res=mid,l=mid+1; 42 else r=mid-1; 43 } 44 ans+=res; 45 } 46 printf("%lld",ans); 47 }
手写hash_table之类的还是算了吧 map就完事了