文章目錄
- 問你長度為N的串中不包含了模式串的串有幾個
- 問你長度為1~N的串中包含了模式串的串總共有幾個
矩陣乘法:http://blog.csdn.net/vsooda/article/details/8510131
構造trie圖,繼而構造出初始矩陣,mat[i][j]表示i走到j有幾種走法 ,這個矩陣自乘n次之後就表示i走到j走n步有幾種走法
問你長度為N的串中不包含了模式串的串有幾個
n屬於1 ~ 2000000000看到這個資料範圍我們就應該敏感的想到這是矩陣~
最多100個結點,先建好所有結點(不包括模式串結尾的和fail指向結尾的結點,所以其實最多隻有90個有效結點)之間的轉化關係,然後二分矩陣乘法,複雜度O(100^3*log(2000000000))
#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;const int mod = 100000;const int M = 100;const int CD = 4;int fail[M];int Q[M];int ch[M][CD];int ID[128];int val[M];int sz;void Init(){fail[0]=0;memset(ch[0],0,sizeof(ch[0]));sz=1;ID['A']=0;ID['T']=1;ID['G']=2;ID['C']=3;}void Insert(char *s){int p=0;for(;*s;s++){int c=ID[*s];if(!ch[p][c]){memset(ch[sz],0,sizeof(ch[sz]));val[sz]=0;ch[p][c]=sz++;}p=ch[p][c];}val[p]=1;}void Construct(){int *s=Q,*e=Q;for(int i=0;i<CD;i++){if(ch[0][i]){fail[ch[0][i]] = 0;*e++ = ch[0][i];}}while(s!=e){int u = *s++;for(int i=0;i<CD;i++){int &v = ch[u][i];if(v){*e++ = v;fail[v]=ch[fail[u]][i];val[v]|=val[fail[v]];} else {v=ch[fail[u]][i];}}}}long long dp[100][100];const int MAX = 100;int n;struct Mat {int mat[MAX][MAX];Mat(){memset(mat,0,sizeof(mat));}void init(){for(int i=0;i<n;i++)for(int j=0;j<n;j++)mat[i][j]= i==j;}void print(){printf("****************\n");for(int i=0;i<n;i++) for(int j=0;j<n;j++)printf(j==n-1?"%d\n":"%d ",mat[i][j]);printf("fuckfuckfuckfuckfuck\n");}friend Mat operator *(Mat a,Mat b);friend Mat operator +(Mat a,Mat b);friend Mat operator ^(Mat a,int k);}E;Mat operator +(Mat a,Mat b){Mat c;for(int i=0;i<n;i++)for(int j=0;j<n;j++){c.mat[i][j]=a.mat[i][j]+b.mat[i][j];if(c.mat[i][j]>=mod) c.mat[i][j]-=mod;}return c;}Mat operator *(Mat a,Mat b){Mat ans;for(int i=0;i<n;i++)for(int j=0;j<n;j++){long long tmp=0;for(int k=0;k<n;k++){tmp+=(long long)a.mat[i][k]*b.mat[k][j];}ans.mat[i][j]=tmp%mod;}return ans;}Mat operator ^(Mat a,int k){Mat ans=E;while(k){if(k&1) ans=ans*a;a=a*a,k>>=1;}return ans;}int main() {char s[15];int k,m;while(scanf("%d%d",&m,&k)!=EOF){Init();for(int i=0;i<m;i++) {scanf("%s",s);Insert(s);}Construct();n=sz;Mat ans;for(int i=0;i<sz;i++){if(val[i])continue;for(int j=0;j<4;j++){if(val[ch[i][j]])continue;ans.mat[i][ch[i][j]]++;}}E.init();ans=ans^k;int ret=0;for(int i=0;i<n;i++){ret+=ans.mat[0][i];if(ret>=mod) ret-=mod;}printf("%d\n",ret);}return 0;}
HDU 2243
問你長度為1~N的串中包含了模式串的串總共有幾個
上題的加強版,先要把總數26^1 + 26^2 + … + 26^N算出來,然後減去所有不包含的…反正比上題噁心一點點
答案要模2^64,直接用unsinged __int64 就OK了
#include<cstdio>#include<cstring>typedef unsigned __int64 ULL;const int MAX = 65;int n,k,m,tn;struct Mat {ULL mat[MAX][MAX];friend Mat operator *(Mat a,Mat b);friend Mat operator +(Mat a,Mat b);friend Mat operator ^(Mat a,int k);}E,A;ULL a[MAX][MAX];Mat operator +(Mat a,Mat b){Mat c;memset(c.mat,0,sizeof(c.mat));for(int i=0;i<n;i++)for(int j=0;j<n;j++)c.mat[i][j]=(a.mat[i][j]+b.mat[i][j]);return c;}Mat operator *(Mat a,Mat b){Mat ans;memset(ans.mat,0,sizeof(ans.mat));for(int i=0;i<n;i++)for(int j=0;j<n;j++)for(int k=0;k<n;k++){ULL tmp=a.mat[i][k]*b.mat[k][j];ans.mat[i][j]=ans.mat[i][j]+tmp;}return ans;}Mat operator ^(Mat a,int k){for(int i=0;i<n;i++) for(int j=0;j<n;j++) E.mat[i][j]= (i==j);Mat ans=E;while(k){if(k&1) ans=ans*a;a=a*a,k>>=1;}return ans;}const int M = 100;const int CD = 26;int fail[M];int Q[M];int ch[M][CD];int ID[128];int sz;int flag[M];void Init() {fail[0]=0;memset(ch[0],0,sizeof(ch[0]));sz=1;for(int i=0;i<26;i++) ID[i+'a']=i;}void Insert(char *s){int p=0;for(;*s;s++){int c=ID[*s];if(!ch[p][c]){memset(ch[sz],0,sizeof(ch[sz]));flag[sz]=0;ch[p][c]=sz++;}p=ch[p][c];}flag[p]=1;}void Construct(){int *s=Q,*e=Q,v;for(int i=0;i<CD;i++){if(ch[0][i]){fail[ch[0][i]]=0;*e++ = ch[0][i];}}while(s!=e){int u = *s++;for(int i=0;i<CD;i++){if(v=ch[u][i]){*e++=v;fail[v]=ch[fail[u]][i];flag[v]|=flag[fail[v]];}else {ch[u][i]=ch[fail[u]][i];}}}}void init(){memset(A.mat,0,sizeof(A.mat));for(int i=0;i<tn;i++){for(int j=0;j<tn;j++){A.mat[i][j]=a[i][j];A.mat[i][j+tn]=a[i][j];}}for(int i=tn;i<n;i++){for(int j=tn;j<n;j++){if(i==j)A.mat[i][j]=1;}}}int main(){ int N;int L;char s[10];while(scanf("%d%d",&N,&L)!=EOF){memset(a,0,sizeof(a));tn=1; a[0][0]=26; n=2*tn; init();Mat ans=A^L;ULL sum=ans.mat[0][1];Init();for(int i=0;i<N;i++){scanf("%s",s);Insert(s);}Construct();Mat dp;memset(dp.mat,0,sizeof(dp.mat));for(int i=0;i<sz;i++)if(!flag[i]){for(int j=0;j<CD;j++) if(!flag[ch[i][j]]){dp.mat[i][ch[i][j]]++;}}memset(a,0,sizeof(a));for(int i=0;i<sz;i++){for(int j=0;j<sz;j++){a[i][j]=dp.mat[i][j];}}tn=sz; n=2*tn; init();ans=A^L;ULL sum2=0;for(int j=tn;j<n;j++){sum2+=ans.mat[0][j];}printf("%I64u\n",(sum-sum2));}return 0;}