[容斥] Hihocoder Challenge 32 .B Rikka with String II

来源:互联网 发布:有没有5g网络 编辑:程序博客网 时间:2024/05/14 23:23

字典树实际上就是把前缀给缩起来

如果只有两个串,那么答案就是两个串的长度和减去LCP

这就是个容斥的形式,答案就是 2?+SU(1)|S|+1LCP(S)

前面的 2? 是根节点

LCP的话,枚举一下每一位,判断一下就可以了

hihocoder跑得好快啊,竟然没被卡常

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <vector>#include <ctime>#define pb push_backusing namespace std;const int N=25,P=998244353;int n,len[N],pw[25*50],pre[N][55],ipre[55];char a[N][N<<2];char *c[N];int t;int main(){  freopen("1.in","r",stdin);  freopen("1.out","w",stdout);  pw[0]=1;  for(int i=1;i<=20*50;i++) pw[i]=2*pw[i-1]%P;  scanf("%d",&n);  for(int i=1;i<=n;i++){    scanf("%s",a[i]+1),len[i]=strlen(a[i]+1);    for(int j=len[i];j;j--)      pre[i][j]=pre[i][j+1]+(a[i][j]=='?');  }  int ans=1;  for(int i=1;i<=n;i++) ans=1LL*ans*pw[pre[i][1]]%P;  for(int S=1;S<(1<<n);S++){    int size=0; int mlen=1<<30;    for(int i=1;i<=n;i++)      if((S>>(i-1))&1) c[size++]=a[i],mlen=min(mlen,len[i]);    int cur=0,p=0,prod=1;    ipre[51]=0;    for(int i=50;i;i--){      ipre[i]=ipre[i+1];      for(int j=0;j<size;j++)    ipre[i]+=(c[j][i]=='?');    }    for(int i=1;i<=mlen;i++,p++){      int cnt0=0,cnt1=0;      for(int j=0;j<size;j++){    if(c[j][i]=='0') cnt0++;    if(c[j][i]=='1') cnt1++;      }      if(cnt0 && cnt1) break;      if(!cnt0 && !cnt1){    int pd=1LL*(pw[size]-2)*(i-1)%P;    pd=1LL*pd*pw[ipre[i+1]]%P;    cur=(cur+1LL*prod*pd)%P;    prod=2*prod%P;    continue;      }      int r=size-cnt0-cnt1,pd=1LL*(pw[r]-1)*(i-1)%P;      //for(int j=0;j<size;j++) pd=1LL*pd*pw[pre[c[j]][i+1]]%P;      pd=1LL*pd*pw[ipre[i+1]]%P;      cur=(cur+1LL*prod*pd)%P;    }    int pd=pw[ipre[p+1]];    //for(int j=0;j<size;j++) pd=1LL*pd*pw[pre[c[j]][p+1]]%P;    cur=(cur+1LL*prod*p%P*pd)%P;    for(int i=1;i<=n;i++)      if(!((S>>(i-1))&1)) cur=1LL*cur*pw[pre[i][1]]%P;    if(size&1) ans=(ans+cur)%P;    else ans=(ans-cur)%P;  }  printf("%d\n",(ans+P)%P);  //printf("%d\n",clock());  return 0;}
原创粉丝点击