https://vjudge.net/contest/177933#overview
H HDU3068
做法:马拉车模板
#include <bits/stdc++.h>
using namespace std;
const int maxn= 110015;
char s[maxn];
char str[maxn*2];
int dp[maxn*2];
int mlc()
{
int n=strlen(s+1);
str[0]='@';
for(int i=2;i<=2*n;i+=2)
{
str[i-1] = '#' ;
str[i]=s[i/2] ;
}
str[2*n+1] = '#';
str[2*n+2] = '0';
str[2*n+3] = 0;
memset(dp,0,sizeof(dp));
int ans=0 ,mx=0,id=0;
for(int i=1;i<=2*n+1;++i)
{
mx>i? dp[i]=min(dp[2*id-i],mx-i) :dp[i]=1 ;
while(str[i-dp[i]] == str[i+dp[i]]) dp[i]++;
if(dp[i]+i>mx)
{
mx=dp[i]+i;
id=i;
}
ans=max(ans,dp[i]);
}
return ans-1;
}
int main()
{
while(scanf("%s",s+1)!=EOF)
{
printf("%d\n",mlc());
}
return 0;
}
POJ 2406
做法: KMP 最小循环节 N-NEXT[N] 前提(N%(N-NEXT[N])==0)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=1e6+10;
char s[maxn];
int next[maxn];
int len;
void getnext()
{
int j,k;
j=0; next[0] = k =-1;
while(j<len)
{
if(k==-1 || s[j]==s[k]) next[++j]=(++k);
else k=next[k];
}
}
int main()
{
while(scanf("%s",s)!=EOF)
{
if(s[0]=='.') break;
len=strlen(s);
getnext();
int temp = len-next[len];
if(len%temp==0)
{
printf("%d\n",len/temp);
}
else
{
printf("1\n");
}
}
return 0;
}
HDU 2222
做法:AC自动机模板
#include <bits/stdc++.h>
using namespace std;
struct trie
{
int next[500010][26],fail[500010],end[500010];
int root , tot;
int newnode()
{
for(int i=0;i<26;++i)
{
next[tot][i]=-1;
}
end[tot++] = 0;
return tot-1;
}
void init()
{
tot=0;
root = newnode();
}
void push(char str[])
{
int len=strlen(str);
int now=root;
for(int i=0;i<len;++i)
{
if(next[now][str[i]-'a']== -1)
{
next[now][str[i]-'a'] = newnode();
}
now = next[now][str[i]-'a'];
}
end[now]++;
}
void build()
{
queue<int> que;
fail[root] = root;
for(int i=0;i<26;++i)
{
if(next[root][i]==-1) next[root][i]=root;
else
{
fail[next[root][i]]=root;
que.push(next[root][i]);
}
}
while(!que.empty())
{
int now=que.front() ; que.pop();
for(int i=0;i<26;++i)
{
if(next[now][i]==-1)
{
next[now][i]=next[fail[now]][i];
}
else
{
fail[next[now][i]]=next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}
int query(char str[])
{
int len=strlen(str);
int now=root;
int ans=0;
for(int i=0;i<len;++i)
{
now= next[now][str[i]-'a'];
int temp = now;
while(temp!=root)
{
ans+=end[temp];
end[temp]=0;
temp=fail[temp];
}
}
return ans;
}
}ac;
char s[1000010];
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
ac.init();
for(int i=0;i<n;++i)
{
scanf("%s",s);
ac.push(s);
}
ac.build();
scanf("%s",s);
printf("%d\n",ac.query(s));
}
return 0;
}
POJ 2778
做法:只需要把病毒串标记。然后对没有标记在矩阵上记录权值(如果next节点不存在也要记录),套一个矩阵快速幕即可!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const ll mod =1e5;
struct matirx
{
ll mu[105][105];
matirx()
{
for(int i=0;i<105;++i)
{
for(int j=0;j<105;++j)
{
mu[i][j]=0;
}
}
}
};
int turn(char c)
{
if(c=='A') return 0; if(c=='G') return 1;
if(c=='C') return 2; if(c=='T') return 3;
}
struct tire
{
int next[105][4],fail[105],end[105];
int root,tot;
int newnode()
{
for(int i=0;i<4;++i)
{
next[tot][i]=-1;
}
end[tot++]=0;
return tot-1;
}
void init()
{
tot=0;
root=newnode();
}
void push(char str[])
{
int len=strlen(str);
int now=root;
for(int i=0;i<len;++i)
{
if(next[now][turn(str[i])]==-1)
{
next[now][turn(str[i])] = newnode();
}
now=next[now][turn(str[i])];
}
end[now]=1;
}
void build()
{
queue<int> que;
fail[root] = root;
for(int i=0;i<4;++i)
{
if(next[root][i]==-1)
{
next[root][i]=root;
}
else
{
fail[next[root][i]] = root;
que.push(next[root][i]);
}
}
while(!que.empty())
{
int now=que.front() ;que.pop();
if(end[fail[now]]) end[now]=1;
for(int i=0;i<4;++i)
{
if(next[now][i]==-1)
{
next[now][i]=next[fail[now]][i];
}
else
{
fail[next[now][i]] = next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}
}ac;
matirx muilt(matirx a ,matirx b)
{
matirx ans;
for(int i=0;i<ac.tot;++i)
{
for(int k=0;k<ac.tot;++k)
{
for(int j=0;j<ac.tot;++j)
{
ans.mu[i][j] = ( ans.mu[i][j] + a.mu[i][k] * b.mu[k][j] )%mod;;
}
}
}
return ans;
}
matirx pow(matirx bit ,ll n)
{
matirx ans;
for(int i=0;i<ac.tot;++i) ans.mu[i][i]=1;
while(n)
{
if( n & 1) ans = muilt(ans,bit);
bit = muilt(bit,bit);
n>>=1;
}
return ans;
}
matirx getbit()
{
matirx x;
for(int i=0;i<ac.tot;++i)
{
for(int j=0;j<4;++j)
{
if(!ac.end[ac.next[i][j]])
{
x.mu[i][ac.next[i][j]]++;
}
}
}
return x;
}
char s[100500];
int main()
{
int n;
ll m;
while(scanf("%d%I64d",&n,&m)!=EOF)
{
ac.init();
for(int i=0;i<n;++i)
{
scanf("%s",s);
ac.push(s);
}
ac.build();
matirx bit = getbit();
matirx ans = pow(bit,m);
ll sum=0;
for(int i=0;i<ac.tot;++i)
{
sum = (sum+ans.mu[0][i])%mod;
}
printf("%lld\n",sum);
}
return 0;
}
HDU 2852
做法:AC自动机 + 状压dp
AC自动机上维护状态转移,对每个key进行表号,并用s表示,注意如果fail链指向标记也要进行标记
#include <bits/stdc++.h>
using namespace std;
int n,m,k;
int num[1<<12];
int dp[30][105][1<<12];
const int mod=20090717;
struct tire
{
int next[105][26] , end[105] ,fail[105];
int tot,root;
int newnode()
{
for(int i=0;i<26;++i) next[tot][i]=-1;
end[tot++]=0;
return tot-1;
}
void init()
{
tot=0;
root = newnode();
}
void pusuh(char s[],int cnt)
{
int len=strlen(s);
int now=root;
for(int i=0;i<len;++i)
{
if(next[now][s[i]-'a']==-1) next[now][s[i]-'a'] = newnode();
now = next[now][s[i]-'a'];
}
end[now]|=(1<<cnt);
}
void build()
{
fail[root]=root;
queue<int> que;
for(int i=0;i<26;++i)
{
if(next[root][i]==-1) next[root][i] = root;
else
{
fail[next[root][i]] = root;
que.push(next[root][i]);
}
}
while(!que.empty())
{
int now=que.front(); que.pop();
end[now]|=end[fail[now]];
for(int i=0;i<26;++i)
{
if(next[now][i]==-1)
{
next[now][i]=next[fail[now]][i];
}
else
{
fail[next[now][i]] = next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}
int work()
{
for(int i=0;i<=n;++i)
{
for(int j=0;j<tot;++j)
{
for(int k=0;k<(1<<m);++k)
{
dp[i][j][k]=0;
}
}
}
dp[0][0][0]=1;
for(int i=0;i<n;++i)
{
for(int j=0;j<tot;++j)
{
for(int k=0;k<(1<<m);++k)
{
if(!dp[i][j][k]) continue;
for(int t=0;t<26;++t)
{
dp[i+1][next[j][t]][k|end[next[j][t]]] = ( dp[i+1][next[j][t]][k|end[next[j][t]]]+dp[i][j][k] )%mod;
}
}
}
}
int ans=0;
for(int i=0;i<(1<<m);++i)
{
if(num[i]<k) continue;
for(int j=0;j<tot;++j)
ans= (ans+dp[n][j][i])%mod;
}
return ans;
}
}ac;
char s[105];
int main()
{
memset(num,0,sizeof(num));
for(int i=0;i<(1<<10);++i)
{
for(int j=0;j<10;++j)
{
if(i&(1<<j)) num[i]++;
}
}
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
if(n==0&&m==0&&k==0) break;
ac.init();
for(int i=0;i<m;++i)
{
scanf("%s",s);
ac.pusuh(s,i);
}
ac.build();
printf("%d\n",ac.work());
}
return 0;
}
HDU 2774
做法:后缀数组:将两个串放在一起,然后在中间加一个标记即可。答案就在 rank排名的交界处 ,一定要满足两个sa在不同的串内, 然后求最大的height
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=5e5+10;
char s1[maxn],s2[maxn],s[maxn<<1];
int sa[maxn],t1[maxn],t2[maxn],c[maxn<<1];
int rk[maxn],height[maxn];
void getsa(int n,int m)
{
int *x=t1,*y=t2;
for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<n;++i) c[x[i]=s[i]]++;
for(int i=1;i<m;++i) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;++i) y[p++]=i;
for(int i=0;i<n;++i)
if(sa[i]>=k) y[p++] = sa[i]-k;
for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<n;++i) c[x[y[i]]]++;
for(int i=1;i<m;++i) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1; x[sa[0]]=0;
for(int i=1;i<n;++i)
x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
void gethight(int n)
{
int k=0;
for(int i=0;i<n;++i) rk[sa[i]]=i;
for(int i=0;i<n;++i)
{
if(k) k--;
else k=0;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
}
int main()
{
while(scanf("%s%s",s1,s2)!=EOF)
{
int pos=0;
for(int i=0;s1[i];++i) s[pos++] = s1[i]-'a'+1;
s[pos++]=28;
for(int i=0;s2[i];++i) s[pos++] = s2[i]-'a'+1;
s[pos++]=0;
getsa(pos,29);
gethight(pos);
int ans=0, len = strlen(s1);
for(int i=2;s[i];++i)
{
if(height[i]>ans)
{
if(sa[i-1]>=0 &&sa[i-1]<len&&len<sa[i]) ans=height[i];
if(0<=sa[i] && sa[i]<len &&len<sa[i-1]) ans=height[i];
}
}
printf("%d\n",ans);
}
return 0;
}
POJ 3261
求重复k次以上的最长重复子串
做法:套完板子之后,二分答案,将heigh大于mid的分为一组如果有超过k个则检验成功
板子使用注意一些地方
getsa(n+1,maxn+2);
m基数取比最大的数稍大即可。最后串加个s[N]=0; hight是从2开始的!!!
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn=20010;
int s[maxn<<1];
int sa[maxn],t1[maxn],t2[maxn],c[maxn<<1];
int rk[maxn],height[maxn];
void getsa(int n,int m)
{
int *x=t1,*y=t2;
for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<n;++i) c[x[i]=s[i]]++;
for(int i=1;i<m;++i) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;++i) y[p++]=i;
for(int i=0;i<n;++i)
if(sa[i]>=k) y[p++] = sa[i]-k;
for(int i=0;i<m;++i) c[i]=0;
for(int i=0;i<n;++i) c[x[y[i]]]++;
for(int i=1;i<m;++i) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1; x[sa[0]]=0;
for(int i=1;i<n;++i)
x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
void gethight(int n)
{
int k=0,j;
for(int i=0;i<=n;++i) rk[sa[i]]=i;
for(int i=0;i<n;++i)
{
if(k) k--;
j=sa[rk[i]-1];
while(s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
}
bool judge(int mid,int n,int kk)
{
int num=1;
for(int i=2;i<=n;++i)
{
if(height[i]>=mid)
{
num++;
if(num>=kk) return 1;
}
else num=1;
}
return 0;
}
int main()
{
int n,kk;
while(scanf("%d%d",&n,&kk)!=EOF)
{
int maxn=0;
for(int i=0;i<n;++i) { scanf("%d",&s[i]); maxn=max(maxn,s[i]);}
s[n]=0;
getsa(n+1,maxn+2);
gethight(n);
int l=0,r=n;
int ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid,n,kk)) {ans = max(ans,mid); l=mid+1;}
else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}