以后就是 $NOI$ 模拟赛了!!!

题目

WZJ题解

 

T1

一开考就口胡了这道题……

首先遇到这种总字符数特别少的多模板串匹配,肯定要建一个 $AC$ 自动机。

然后想到了维护矩阵,同时记录 转移到的点 和 匹配过的点的集合。

但是这样的复杂度是 $O((50\times m)^3\times log(n))$,会被卡。

所以不能维护 匹配过的点的集合,把它抽到外面去,这样能省很多矩乘复杂度。

不知道你还记不记得这么一道题:GT考试

那一题是不让你匹配出不吉利数字串。

然后回来看看这题,发现两者求的东西其实是相反的。

所以这题可以枚举不出现哪些串,在预处理转移矩阵时,不让根节点能够转移到一个点,使得根节点到这个点的路径组成的串的后缀为一个不能出现的串。

由于转移矩阵经过一次转移,最多多匹配一位,也就是匹配到它的儿子,所以对于一个后缀为一个不能出现的串的串在 $AC$ 自动机上的底部节点(可能不存在,那就不用管),当匹配到这个点的父亲时,判断一下,不让它匹配到这个点就行了。这样就没法转移到这个点及其下面的所有点了。

最后套一个容斥原理就行了:不出现任意一个串的情况数 = 不出现 $1$ 个串的情况数 - 不出现 $2$ 个串的情况数 + 不出现 $3$ 个串的情况数 - 不出现 $4$ 个串的情况数。

答案就是 总情况数 - 不出现任意一个串的情况数。

时间复杂度 $O(2^m\times 50^3\times log(n))$。

 

另外一定要搞清矩阵的横乘和纵乘是不一样的!!横乘是 $a(i,k)\times b(k,j)$,纵乘是 $b(i,k)\times a(k,j)$!!现场用垃圾纵乘然后写反,成功表演爆 $0$……

  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 #define mod 998244353
  4 using namespace std;
  5 inline int read(){
  6     int x=0; bool f=1; char c=getchar();
  7     for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
  8     for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
  9     if(f) return x;
 10     return 0-x;
 11 }
 12 int m,mm,n,tag[55];
 13 ll f[55][55],ans;
 14 char c[5][55];
 15 
 16 int que[55],nxt[55];
 17 namespace AC{
 18     int tr[55][26],Tr[55][26],mark[55],cnt;
 19     void ins(char ch[55],int id){
 20         int len=strlen(ch),i,u=0,v;
 21         for(i=0;i^len;++i){
 22             v=ch[i]^'0';
 23             if(!tr[u][v]) tr[u][v]=Tr[u][v]=++cnt;
 24             u=tr[u][v];
 25         }
 26         mark[u]|=(1<<id);
 27     }
 28     void getFail(){
 29         int i,u,hd=1,tl=0;
 30         for(int i=0;i^10;++i) if(tr[0][i]) que[++tl]=tr[0][i];
 31         while(hd<=tl){
 32             u=que[hd++], mark[u]|=mark[nxt[u]];
 33             for(i=0;i^10;++i){
 34                 if(!tr[u][i]) {tr[u][i]=tr[nxt[u]][i];}
 35                 else{
 36                     que[++tl]=tr[u][i];
 37                     nxt[tr[u][i]]=tr[nxt[u]][i];
 38                 }
 39             }
 40         }
 41     }
 42 };
 43 using namespace AC;
 44 void mul(ll a[55][55], ll b[55][55]){
 45     int i,j,k; ll tmp[55][55];
 46    /* cout<<"++"<<endl;
 47     for(i=0;i<=cnt;++i){
 48             for(j=0;j<=cnt;++j)
 49                 printf("%d ",b[i][j]);
 50             putchar('\n');
 51         }*/
 52     //cout<<"++"<<endl;
 53     for(i=0;i<=cnt;++i)
 54         for(j=0;j<=cnt;++j){
 55             tmp[i][j]=0;
 56             for(k=0;k<=cnt;++k)
 57                 (tmp[i][j]+=a[k][j]*b[i][k])%=mod;
 58         }
 59     for(i=0;i<=cnt;++i)
 60         for(j=0;j<=cnt;++j)
 61             a[i][j]=tmp[i][j];
 62 }
 63 ll a[55][55],b[55][55];
 64 ll qpow(ll x,int y){
 65     ll ret=1;
 66     while(y>0){
 67         if(y&1) ret=(ret*x)%mod;
 68         x=(x*x)%mod;
 69         y>>=1;
 70     }
 71     return ret;
 72 }
 73 ll qpow(int x){
 74     int i,j;
 75     memset(a,0,sizeof(a));
 76     a[0][0]=1;
 77     while(x>0){
 78         if(x&1) mul(a,b);
 79         mul(b,b);
 80         x>>=1;
 81     }
 82     ll res=0;
 83     for(i=0;i<=cnt;++i) res=(res+a[i][0])%mod;
 84     return res;
 85 }
 86 void dfs(int u,int x,int mx){
 87     if(u){
 88         memset(b,0,sizeof b);
 89         int i,j,t;
 90         que[1]=0;
 91         /*
 92         for(int hd=1,tl=1;hd<=tl;++hd){
 93             i=que[hd];
 94             for(j=0;j^m;++j)
 95                 if(u&(1<<j) && tag[j]==i){ed[u]=1; break;}
 96             for(j=0;j^10;++j)
 97                 if(Tr[i][j]) que[++tl]=Tr[i][j], ed[Tr[i][j]]=ed[i];
 98         }*/
 99        // for(int j=0;j<=cnt;++j)if(mark[j]&u)ed[j]=1;
100         //cout<<"-------"<<endl;
101         for(i=0;i<=cnt;++i){
102             for(j=0;j^10;++j){
103                 t=tr[i][j];
104                 //printf("back:%d %d %d\n",j,t,i);
105                 if(!(mark[t]&u)) b[t][i]=(b[t][i]+1)%mod;
106             }
107         }
108         /*cout<<"-------"<<endl;
109         for(i=0;i<=cnt;++i){
110             for(j=0;j<=cnt;++j)
111                 printf("%d ",b[i][j]);
112             putchar('\n');
113         }*/
114         ans+=qpow(n)*x;
115       //  printf("Hey buddy:%d %d %lld %lld\n",u,x,haha,ans);
116         ans=(ans%mod+mod)%mod;
117     }
118     if(!(u&1) && (u|1)<mm && 1>mx) dfs(u|1,-x,max(mx,1));
119     if(!(u&2) && (u|2)<mm && 2>mx) dfs(u|2,-x,max(mx,2));
120     if(!(u&4) && (u|4)<mm && 4>mx) dfs(u|4,-x,max(mx,4));
121     if(!(u&8) && (u|8)<mm && 8>mx) dfs(u|8,-x,max(mx,8));
122 }
123 int main(){
124     //freopen("password.in","r",stdin);
125     //freopen("password.out","w",stdout);
126     m=read(),n=read();
127     mm=1<<m;
128     int i,j;
129     for(i=0;i^m;++i){
130         scanf("%s",c[i]);
131         ins(c[i],i);
132     }
133     getFail();
134     dfs(0,-1,0);
135     printf("%lld\n",((qpow(10,n)-ans)%mod+mod)%mod);
136     return 0;
137 }    
View Code

相关文章:

  • 2021-11-18
  • 2022-12-23
  • 2021-10-31
  • 2022-12-23
  • 2021-08-02
  • 2022-12-23
  • 2022-01-02
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-12-19
  • 2021-12-28
  • 2022-12-23
  • 2022-12-23
  • 2021-07-21
相关资源
相似解决方案