BZOJ2272: [Usaco2011 Feb]Cowlphabet 奶牛文字
n<=250个大写字母和m<=250个小写字母,给p<=200个合法相邻字母,求用这些合法相邻字母的规则和n+m个字母能合成多少合法串,答案mod 97654321.
什么鬼膜数。。
f(i,j,k)--i个大写字母,j个小写字母,最后一个字母是k,,其中k是小写字母,p是能接在k前面的任意字母,k是大写字母的话同理。
这样复杂度是n*m*26*26?假的!i,j确定后只有p种合法转移,所以就n*m*p。
trick:记得算i=0和j=0的情况!!!
1 #include<cstring> 2 #include<cstdlib> 3 #include<cstdio> 4 //#include<assert.h> 5 //#include<time.h> 6 #include<math.h> 7 #include<algorithm> 8 //#include<iostream> 9 using namespace std; 10 11 bool isdigit(char c) {return c>='0' && c<='9';} 12 int qread() 13 { 14 char c;int s=0,f=1;while (!isdigit(c=getchar())) f=(c=='-'?-1:1); 15 do s=s*10+c-'0'; while (isdigit(c=getchar())); return s*f; 16 } 17 18 const int mod=97654321; 19 int da,xiao,m; 20 int f[255][255][55]; 21 int id(char c) {return (c>='a' && c<='z')?c-'a':c-'A'+26;} 22 bool isalpha(char c) {return (c>='a' && c<='z') || (c>='A' && c<='Z');} 23 struct Edge{int to,next;}edge[255];int first[55],le=2; 24 void in(int x,int y) {Edge &e=edge[le];e.to=y;e.next=first[x];first[x]=le++;} 25 int main() 26 { 27 da=qread(),xiao=qread(),m=qread(); 28 memset(first,0,sizeof(first)); 29 for (int i=1;i<=m;i++) 30 { 31 char c1,c2; 32 while (!isalpha(c1=getchar())); 33 c2=getchar(); 34 in(id(c2),id(c1)); 35 } 36 for (int i=0;i<26;i++) f[0][1][i]=1,f[1][0][i]=0; 37 for (int i=26;i<52;i++) f[0][1][i]=0,f[1][0][i]=1; 38 for (int i=0;i<=da;i++) 39 for (int j=0;j<=xiao;j++) if (i+j>=2) 40 { 41 if (j) for (int now=0;now<26;now++) 42 { 43 f[i][j][now]=0; 44 for (int k=first[now];k;k=edge[k].next) 45 { 46 const Edge &e=edge[k]; 47 f[i][j][now]+=f[i][j-1][e.to], 48 f[i][j][now]-=f[i][j][now]>=mod?mod:0; 49 } 50 } 51 if (i) for (int now=26;now<52;now++) 52 { 53 f[i][j][now]=0; 54 for (int k=first[now];k;k=edge[k].next) 55 { 56 const Edge &e=edge[k]; 57 f[i][j][now]+=f[i-1][j][e.to], 58 f[i][j][now]-=f[i][j][now]>=mod?mod:0; 59 } 60 } 61 } 62 int ans=0; 63 for (int i=0;i<52;i++) ans+=f[da][xiao][i],ans-=ans>=mod?mod:0; 64 printf("%d\n",ans); 65 return 0; 66 }