HDU2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)

POJ2778一样。这题是求长度不超过n且包含至少一个词根的单词总数。

长度不超过n的单词总数记为Sn长度不超过n不包含词根的单词总数记为Tn

答案就是,Sn-Tn

Sn=26+262+263+...+26n

Tn=A+A2+A3+...+An (A为AC自动机构造出来的矩阵)

可以构造矩阵用快速幂求出Sn和Tn

$$ egin{bmatrix} 26 & 1 \ 0 & 1 end{bmatrix} imes egin{bmatrix} S_n \ 26 end{bmatrix} = egin{bmatrix} S_{n+1} \ 26 end{bmatrix}$$

$$ egin{bmatrix} A & E \ 0 & E end{bmatrix} imes egin{bmatrix} T_n \ A end{bmatrix} = egin{bmatrix} T_{n+1} \ A end{bmatrix}$$

通过 $ egin{bmatrix} 26 & 1 \ 0 & 1 end{bmatrix} ^n imes egin{bmatrix} S_0 \ 26 end{bmatrix} = egin{bmatrix} S_n \ 26 end{bmatrix}$ 即可得到Sn,其中S0=0,Tn同理。

另外题目结果mod 264这个直接把变量定义为unsigned __int64即可,溢出位数自动舍去。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 using namespace std;
  5 int tn,ch[33][26],fail[33];
  6 bool flag[33];
  7 void insert(char *s){
  8     int x=0;
  9     for(int i=0; s[i]; ++i){
 10         int y=s[i]-'a';
 11         if(ch[x][y]==0) ch[x][y]=++tn;
 12         x=ch[x][y];
 13     }
 14     flag[x]=1;
 15 }
 16 void init(int x){
 17     memset(fail,0,sizeof(fail));
 18     queue<int> que;
 19     for(int i=0; i<26; ++i){
 20         if(ch[0][i]) que.push(ch[0][i]);
 21     }
 22     while(!que.empty()){
 23         int x=que.front(); que.pop();
 24         for(int i=0; i<26; ++i){
 25             if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i];
 26             else ch[x][i]=ch[fail[x]][i];
 27             flag[ch[x][i]]|=flag[ch[fail[x]][i]];
 28         }
 29     }
 30 }
 31 void init(){
 32     memset(fail,0,sizeof(fail));
 33     queue<int> que;
 34     for(int i=0; i<26; ++i){
 35         if(ch[0][i]) que.push(ch[0][i]);
 36     }
 37     while(!que.empty()){
 38         int now=que.front(); que.pop();
 39         for(int i=0; i<26; ++i){
 40             if(ch[now][i]) que.push(ch[now][i]),fail[ch[now][i]]=ch[fail[now]][i];
 41             else ch[now][i]=ch[fail[now]][i];
 42             flag[ch[now][i]]|=flag[ch[fail[now]][i]];
 43         }
 44     }
 45 }
 46 struct Mat{
 47     unsigned long long m[66][66];
 48     int n;
 49 };
 50 Mat operator*(const Mat &m1,const Mat &m2){
 51     Mat m={0};
 52     m.n=m1.n;
 53     for(int i=0; i<m.n; ++i){
 54         for(int j=0; j<m.n; ++j){
 55             for(int k=0; k<m.n; ++k) m.m[i][j]+=m1.m[i][k]*m2.m[k][j];
 56         }
 57     }
 58     return m;
 59 }
 60 int main(){
 61     int n,l;
 62     char str[6];
 63     while(~scanf("%d%d",&n,&l)){
 64         tn=0;
 65         memset(ch,0,sizeof(ch));
 66         memset(flag,0,sizeof(flag));
 67         while(n--){
 68             scanf("%s",str);
 69             insert(str);
 70         }
 71         init();
 72         Mat se={0},sm={0};
 73         se.n=sm.n=2;
 74         for(int i=0; i<2; ++i) se.m[i][i]=1;
 75         sm.m[0][0]=26; sm.m[0][1]=1; sm.m[1][1]=1;
 76         n=l;
 77         while(n){
 78             if(n&1) se=se*sm;
 79             sm=sm*sm;
 80             n>>=1;
 81         }
 82         unsigned long long tot=se.m[0][1]*26;
 83 
 84         Mat te={0},tm={0};
 85         te.n=tm.n=tn+1<<1;
 86         for(int i=0; i<te.n; ++i) te.m[i][i]=1;
 87         for(int i=0; i<=tn; ++i){
 88             tm.m[i+tn+1][i+tn+1]=tm.m[i][i+tn+1]=1;
 89         }
 90         for(int i=0; i<=tn; ++i){
 91             if(flag[i]) continue;
 92             for(int j=0; j<26; ++j){
 93                 if(flag[ch[i][j]]) continue;
 94                 ++tm.m[i][ch[i][j]];
 95             }
 96         }    
 97         Mat tmp=tm; tmp.n=tn+1;
 98         n=l;
 99         while(n){
100             if(n&1) te=te*tm;
101             tm=tm*tm;
102             n>>=1;
103         }
104         Mat tmp2; tmp2.n=tn+1;
105         for(int i=0; i<=tn; ++i){
106             for(int j=tn+1; j<te.n; ++j) tmp2.m[i][j-tn-1]=te.m[i][j];
107         }
108         tmp=tmp*tmp2;
109         unsigned long long res=0;
110         for(int i=0; i<=tn; ++i){
111             res+=tmp.m[0][i];
112         }
113         printf("%llu
",tot-res);
114     }
115     return 0;
116 }
原文地址:https://www.cnblogs.com/WABoss/p/5168429.html