2790: GAUSS 2014
Time Limit: 1000 MS Memory Limit: 65536 KBTotal Submit: 12 Accepted: 7 Page View: 20
Submit Status Discuss
Description
GAUSS 2014电磁轨道反器材步枪,是上决╇ф最强大的武器,但是由于年久失修,性能急剧下降。所以上决╇ф决定重构GAUSS 2014。
为了简化问题,可以将GAUSS 2014看作一个长度为n
的且只包含小写字母字符串,且不包含一个特定的字符串。上决╇ф想知道构造GAUSS 2014能有多少种方案。
Input
第一行包含一个正整数n
(1≤n≤109
)。表示GAUSS 2014字符串的长度。
接下来一个,一个长度不超过20的字符串,为GAUSS 2014所不包含的特定字符串。
接下来一个,一个长度不超过20的字符串,为GAUSS 2014所不包含的特定字符串。
Output
输出一行,包含一个整数,为能构造的GAUSS 2014的方案数,结果对109+7
取模
4
a
390625
Source
Tags
分析:
题目要求不包含指定的字符串,设该字符串的长度为k,那么在构造的时候。
可以把合法状态分为k种,0到k-1,分别代表末尾能够匹配的长度。
用KMP或者AC自动机能够处理出这些状态之间的转移关系。
用dp[i][j]表示目前的状态为i,长度为j,dp[i][j]=∑dp[m][j-1] (m<=k-1且m状态能够转移到i状态)
由于题目中n的范围很大,所以不能直接dp,要把dp的关系式改成矩阵快速幂。
代码如下
KMP
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; string a; int trans[25][30]; int num[26][26]; const int MOD=1e9+7; const int N = 30; int Next[N]; typedef long long LL; int flag; #define mod(x) ((x)%MOD) void getNext(string T,int tlen) { int j, k; j = 0; k = -1; Next[0] = -1; while(j < tlen) if(k == -1 || T[j] == T[k]) Next[++j] = ++k; else k = Next[k]; } struct mat{ LL m[30][30]; }unit; mat r; mat ans; void init_unit(){ for(LL i = 0;i < 26;i++) unit.m[i][i] = 1; return ; } mat operator *(mat a,mat b){ mat ret; LL x; for(LL i = 0;i <25 ;i++){ for(LL j = 0;j < 25;j++){ x = 0; for(LL k = 0;k < 25;k++) { x += mod((LL)a.m[i][k]*b.m[k][j]); // if(i==0&&j==0&&flag==1) // cout<<x<<" "<<i<<" "<<k<<" "<<j<<endl; } ret.m[i][j] = mod(x); } } return ret; }; mat pow_mat(mat a,LL n){ mat ret = unit; while(n){ if(n&1) ret = ret*a; a = a*a; n >>= 1; } return ret; } void init() { memset(Next,0,sizeof(Next)); memset(trans,0,sizeof(trans)); memset(num,0,sizeof(num)); memset(r.m,0,sizeof(r.m)); memset(ans.m,0,sizeof(ans.m)); } int main() { int n; while(cin>>n>>a) { init(); LL res=0; int len=a.size(); getNext(a,len); for(int i=0;i<len;i++) { trans[i][a[i]-'a']=i+1; //表示i状态加上字母后到达新的状态 int h=Next[i]; while(h>=0) { trans[i][a[h]-'a']=max(trans[i][a[h]-'a'],h+1); h=Next[h]; } } for(int i=0;i<len;i++) for(int j=0;j<26;j++) { int k=trans[i][j]; num[k][i]++; //表示k状态由i状态转移过来的数量 } for(int i=0;i<len;i++) for(int j=0;j<len;j++) { r.m[i][j]=num[i][j]; } init_unit(); r=pow_mat(r,n); ans.m[0][0]=1; ans=r*ans; for(int i=0;i<len;i++) res=(res+ans.m[i][0])%MOD; cout<<res<<endl; } return 0; }