【题解】
考虑动态规划的状态转移:
从左往右,加入第n个结点时,只考虑它向前连的边,那么答案就与向前连哪些边,以及之前的n-1个点构成的答案有关2.别忘记取模
【代码】
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MOD 65521 typedef long long LL; LL f[60],count[10]; int S[60],num[10],link[10],change[10],shi[10]; int k,p=0; struct juzhen { LL s[60][60]; juzhen() { memset(s,0,sizeof(s)); } }; juzhen DW; juzhen cheng(juzhen a,juzhen b) { juzhen res; int i,j,l; for(i=1;i<=p;i++) for(j=1;j<=p;j++) { for(l=1;l<=p;l++) res.s[i][j]+=a.s[i][l]*b.s[l][j]; res.s[i][j]%=MOD; } return res; } juzhen ksm(juzhen a,LL n) { juzhen ans=DW,t=a; for(;n>0;n=n>>1) { if(n&1) ans=cheng(ans,t); t=cheng(t,t); } return ans; } int max(int a,int b) { if(a>b) return a; return b; } void init() { int i; for(i=1;i<60;i++) DW.s[i][i]=1; shi[0]=1; shi[1]=10; shi[2]=100; shi[3]=1000; shi[4]=10000; shi[5]=100000; count[0]=count[1]=count[2]=1; count[3]=3; count[4]=16; count[5]=125; } void getS(int i,int Max) { int j; if(i>k) { p++; for(j=1;j<=k;j++) S[p]=S[p]*10+num[j]; return; } for(j=0;j<=Max;j++) { num[i]=j; getS(i+1,max(Max,j+1)); } } int main() { juzhen g; LL n,I,ans=0; int i,j,l,t,t2; scanf("%d%lld",&k,&n); init(); getS(1,0); for(i=1;i<=p;i++)//枚举连续k位的所有状态 { memset(num,0,sizeof(num)); for(j=0;j<k;j++) num[ (S[i]/shi[j]) % 10 ]++; for(j=0;j<=(1<<k)-1;j++)//枚举连接方式 { memset(link,0,sizeof(link)); t=S[i]; for(l=j;l>0;l=l>>1) { link[t%10]+=l&1; t/=10; } for(l=0;l<k;l++)//排除不合法情况 if(num[l]>1&&link[l]>1) break; if(l<k) continue; if(num[0]==1&&link[0]==0) continue; for(t=0;link[t]==0&&t<k;t++);//计算新状态 t2=0; for(l=k-1;l>=0;l--) { if( link[ (S[i]/shi[l])%10 ] > 0 ) t2=t2*10+t; else t2=t2*10+(S[i]/shi[l])%10; } t2=t2*10+t; for(l=0;l<=k;l++)//用"最小表示法"表示新状态 change[l]=-1; t=-1; for(l=k-1;l>=0;l--)//change:对应法则 if( change[ (t2/shi[l]) % 10 ]==-1 ) change[ (t2/shi[l]) % 10 ]=++t; t=0; for(l=k-1;l>=0;l--) t=t*10+change[(t2/shi[l])%10]; for(l=1;S[l]!=t;l++); g.s[i][l]++; } } for(i=1;i<=p;i++) { memset(num,0,sizeof(num)); for(j=0;j<k;j++) num[ (S[i]/shi[j]) % 10 ]++; f[i]=1; for(j=0;j<k;j++) f[i]*=count[num[j]]; } g=ksm(g,n-k); for(i=1;i<=p;i++) ans+=f[i]*g.s[i][1]; printf("%lld",ans%MOD); return 0; }