今天去上了jsp的上机,感觉以前似乎落下一些知识点。但是没事,我相信我会学会的。。。
今天做了两道AC自动机的题目,感觉跟伸展树一样,AC自动机越来越水了。。。
下午为校赛出了两道题目。虎哥哥告诉我,我要出四道题目。今天先出两道,明天再出两道,爽歪歪。
今天也有一些事情让我很不爽,sad,或许影响到了些许的效率。
AC自动机还有不到10个题,打算这周刷完,然后进军下一个知识点。奋斗吧,小少年。
1,poj-1625- Censored!
我只能说做过E,F这道题目就太水了。
不过这道题目要用到大数的加法。之前大数的加法还写错了一点。真是令人很悲伤。
ans[i][j]:长度为i,状态为j时,有多少种可能性。
ans[i][j]=sum(ans[i-1][k])
#include <cstdio>
#include <cstdlib>
#include <string>
#include <climits>
#include <iostream>
#include <vector>
#include <set>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <sstream>
#include <map>
#include <cstring>
#include <queue>
using namespace std;
#define LL long long
const int MAX_NODE = 15*15;//MAX_NODE = StringNumber * StringLength
const int CHILD_NUM = 55;//节点个数,一般字符形式的题26个
const int mod = 20090717;//特定题目需要
vector<int>vec;
LL dp[501][501];
int ss;
struct BIGnumber
{
int num[101];
int len;
void getnum(LL x)
{
len=0;
if(x==0)
{
num[len++]=0;
return;
}
while(x)
{
num[len++]=x%10;
x=x/10;
}
}
BIGnumber friend operator +(BIGnumber a,BIGnumber b)
{
int alen=a.len;
int blen=b.len;
BIGnumber c;
c.len=0;
int leap=0;
int x;
int i;
for(i=0; i<a.len&&i<b.len; i++)
{
x=a.num[i]+b.num[i]+leap;
c.num[c.len++]=x%10;
leap=x/10;
}
while(i<a.len)
{
x=a.num[i]+leap;
c.num[c.len++]=x%10;
leap=x/10;
i++;
}
while(i<b.len)
{
x=b.num[i]+leap;
c.num[c.len++]=x%10;
leap=x/10;
i++;
}
if(leap)c.num[c.len++]=leap;
return c;
}
void print()
{
for(int i=len-1;i>=0;i--)
{
cout<<num[i];
}
cout<<endl;
}
} ans[55][501],aa,bb;
struct ACAutomaton
{
int chd[MAX_NODE][CHILD_NUM];
int val[MAX_NODE];
int fail[MAX_NODE];
int Q[MAX_NODE];
int ID[256];
int sz;
int chnum;
void init(char str[])
{
fail[0] = 0;
int len=strlen(str);
chnum=len;
for(int i=0; i<len; i++)
{
ID[str[i]]=i;
}
}
void Reset()
{
memset(chd[0] , 0 , sizeof(chd[0]));
memset(val,0,sizeof(val));
sz = 1;
}
void insert(char *a,int key)
{
int p = 0;
int len=strlen(a);
for (int i=0; i<len; i++)
{
int c = ID[a[i]];
if (!chd[p][c])
{
memset(chd[sz] , 0 , sizeof(chd[sz]));
val[sz] = 0;
chd[p][c] = sz ++;
}
p = chd[p][c];
}
val[p] = key;
}
void build_ac()
{
int *s = Q , *e = Q;
for (int i = 0 ; i < chnum; i ++)
{
if (chd[0][i])
{
fail[ chd[0][i] ] = 0;
*e ++ = chd[0][i];
}
}
while (s != e)
{
int u = *s++;
if(val[fail[u]])val[u]=1;
for (int i = 0 ; i < chnum ; i ++)
{
int &v = chd[u][i];
if (v)
{
*e ++ = v;
fail[v] = chd[ fail[u] ][i];
}
else
{
v = chd[ fail[u] ][i];
}
}
}
}
int Work()
{
memset(dp,0,sizeof(dp));
int i,j;
for(i=0; i<sz; i++)
{
if(val[i])continue;
for(j=0; j<chnum; j++)
{
if(val[chd[i][j]])continue;
dp[i][chd[i][j]]++;
}
}
ss=sz;
return 0;
}
void anss(LL m)
{
for(int i=0;i<=m;i++)
{
for(int j=0;j<sz;j++)ans[i][j].getnum(0);
}
ans[0][0].getnum(1);
// ans[0][0].print();
for(int i=1; i<=m; i++)
{
for(int j=0; j<sz; j++)
{
for(int k=0; k<chnum; k++)
{
int c=chd[j][k];
if(val[c])continue;
ans[i][c]=ans[i][c]+ans[i-1][j];
//ans[i][c].print();
}
}
}
aa.getnum(0);
for(int j=0;j<sz;j++)
{
if(val[j])continue;
aa=aa+ans[m][j];
}
aa.print();
}
} AC;
char str[2200000];
char temp[110];
int main()
{
int n,m,p;
while(~scanf("%d%d%d",&n,&m,&p))
{
AC.Reset();
scanf("%s",temp);
AC.init(temp);
for (int i = 1 ; i <=p ; i ++)
{
scanf("%s",temp);
AC.insert(temp,1);
}
AC.build_ac();
AC.Work();
AC.anss(m);
}
return 0;
}
2,hdu-2825- Wireless Password
跟之前的那个题差不多,不过需要记录状态。
dp[i][j][k]:长度为i,节点为j,状态为k的可能性的种数。
用二进制压缩表示k,用滚动数组表示i。
学会了AC自动机,这就是一个模版的过程。
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
const int maxnode=110;
const int childnum=26;
const int mod=20090717;
struct ac_tree
{
int chd[maxnode][childnum];
int val[maxnode];
int fail[maxnode];
int Q[maxnode];
int ID[128];
int sz;
int dp[2][maxnode][1<<10];
void init()
{
fail[0]=0;
for(int i=0;i<childnum;i++)
{
ID[i+'a']=i;
}
}
void reset()
{
memset(chd,0,sizeof(chd));
sz=1;
}
void insert(char str[],int k)
{
int p=0;
int len=strlen(str);
for(int i=0;i<len;i++)
{
int c=ID[str[i]];
if(!chd[p][c])
{
memset(chd[sz],0,sizeof(chd[sz]));
val[sz]=0;
chd[p][c]=sz++;
}
p=chd[p][c];
}
val[p]=k;
}
void ac_build()
{
int *s=Q,*e=Q;
for(int i=0;i<childnum;i++)
{
if(chd[0][i])
{
fail[chd[0][i]]=0;
*e++=chd[0][i];
}
}
while(s!=e)
{
int u=*s++;
for(int i=0;i<childnum;i++)
{
int &v=chd[u][i];
if(v)
{
*e++=v;
fail[v]=chd[fail[u]][i];
val[v]=(val[v]|val[fail[v]]);
}
else v=chd[fail[u]][i];
}
}
}
int word(int n,int m,int k)
{
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
int s=0;
for(int t=1;t<=n;t++)
{
int l=1-s;
memset(dp[l],0,sizeof(dp[l]));
for(int i=0;i<sz;i++)
{
for(int j=0;j<m;j++)
{
if(dp[s][i][j])
{
for(int k=0;k<childnum;k++)
{
int p=chd[i][k];
int st=(j|val[p]);
dp[l][p][st]+=dp[s][i][j];
if(dp[l][p][st]>=mod)dp[l][p][st]-=mod;
}
}
}
}
s=l;
}
int ret=0;
for(int j=0;j<m;j++)
{
int cnt=0;
int st=j;
while(st)
{
cnt+=(st&1);
st>>=1;
}
if(cnt<k)continue;
for(int i=0;i<sz;i++)
{
ret+=dp[s][i][j];
if(ret>=mod)ret-=mod;
}
}
return ret;
}
}AC;
int main()
{
AC.init();
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
if(!(n||m||k))break;
AC.reset();
for(int i=1;i<=m;i++)
{
char temp[55];
scanf("%s",temp);
AC.insert(temp,(1<<(i-1)));
}
AC.ac_build();
printf("%d\n",AC.word(n,1<<m,k));
}
return 0;
}