、

梦熊2026省选集训 Day5 T1

题意

\(T\) 组询问 \(n,m,w\) 求有多少个长为 \(n\) 的 \(01\) 串 \(s\) 和长为 \(m\) 的字符串 \(t\) 使得 \(s,t\) 存在最长公共子串 \(w\)。

\(n,m\leq 100,|w|\leq 3,T\leq 10\)

思路

我们必须利用 \(|w|\) 非常小的性质。考虑设计动态规划。我们记录 \(f_{i,j,s_1,s_2}\) 表示 \(i,j\) 位的末尾有什么。但是这样我们发现我们不知道在 \(i\) 或 \(j\) 后有没有出现一个长度为 \(|w|+1\) 的相同子串。那么我们记 \(f_{i,j,s_1,s_2,p_1,p_2}\),其中 \(p_1,p_2\) 表示 \(s\) 和 \(t\) 中出现的所有长度为 \(|w|+1\) 的 \(01\) 串有没有出现过。但是这样我们发现不需要记录两个了,直接记录 \(f_{i,s_1,p_1}\) 表示同理。这样我们需要查询 \(n,m\) 就转化成了查询

\[\sum_{i\land j=0}f_{n,i}f_{m,j} \]

即可。那么我们发现可以对 \(f_n\) 做一个高维前缀和 \(g\)

\[g_i=\sum_{s\in i}f_s \]

那么我们只需要查寻 \(f_{m,j}\) 中 \(j\) 的补集在 \(g\) 即可。时间复杂度 \(O((n+T)2^{2^{|w|+1}+|w|+1})\)。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const int MAXN=102;
const int MOD=998244353;
int f[MAXN][8][(1<<16)];
int T,n[MAXN],m[MAXN];
string S[MAXN];
void add(int &x,int y){
    x+=y;
    if(x>=MOD){
        x-=MOD;
    }
}
int sa[65540],sb[65540],ans[MAXN];
void solve(int len){
    memset(f,0,sizeof f);
    f[0][0][0]=1;
    rep(i,0,99){
        rep(j,0,(1<<len)-1){
            rep(k,0,(1<<(1<<(len+1)))-1){
                if(i<=len-1){
                    add(f[i+1][(j<<1|1)][0],f[i][j][k]);
                    add(f[i+1][j<<1][0],f[i][j][k]);
                }else{
                    add(f[i+1][(j<<1|1)&((1<<len)-1)][k|(1<<(j<<1|1))],f[i][j][k]);
                    add(f[i+1][(j<<1)&((1<<len)-1)][k|(1<<(j<<1))],f[i][j][k]);
                }
            }
        }
    }
    rep(i,1,T){
        if(S[i].size()!=len){
            continue;
        }
        if(n[i]<len){
            ans[i]=0;
            continue;
        }
        int num=0;
        for(auto v:S[i]){
            num=num*2+v-'0';
        }
        int gv[20];
        rep(j,0,(1<<(len+1))-1){
            gv[j]=((j>>1)==num||(j&((1<<len)-1))==num);
        }
        memset(sa,0,sizeof sa);
        memset(sb,0,sizeof sb);
        rep(j,0,(1<<((1<<(len+1))))-1){
            bool fl=false;
            rep(k,0,(1<<len+1)-1){
                if((j&(1<<k))&&gv[k]){
                    fl=true;
                    break;
                }
            }
            if(fl){
                rep(k,0,(1<<len)-1){
                    add(sa[j],f[n[i]][k][j]);
                    add(sb[j],f[m[i]][k][j]);
                }
            }else{
                add(sa[j],f[n[i]][num][j]);
                add(sb[j],f[m[i]][num][j]);
            }
        }
        rep(j,0,(1<<(len+1))-1){
            rep(k,0,(1<<(1<<(len+1)))-1){
                if((k>>j)&1){
                    add(sa[k],sa[k^(1<<j)]);
                }
            }
        }
        rep(j,0,(1<<(1<<(len+1)))-1){
            int lst=((1<<(1<<(len+1)))-1)^j;
            add(ans[i],1ll*sa[j]*sb[lst]%MOD);
        }
    }
}
int main(){
    freopen("substring.in","r",stdin);
    freopen("substring.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>T;
    rep(i,1,T){
        cin>>n[i]>>m[i]>>S[i];
        if(n[i]>m[i]){
            swap(n[i],m[i]);
        }
    }
    solve(1);
    solve(2);
    solve(3);
    rep(i,1,T){
        cout<<ans[i]<<"\n";
    }
    return 0;
}
posted @ 2026-09-24 14:41  tanghg  阅读(5)  评论(0)    收藏  举报