题解:P15650 [省选联考 2026] 摩卡串 / string

· · 题解

::::info[以下是场上对答案长度上界的极唐诗脑补证明,如果不想看可以跳过。]

::::

总之就是答案若存在,则长度 \le 2m

记答案为 t。记 C_l=\operatorname{LCP}(t_{[l,|t|]},s),R_l=l+C_l-1

记 $f_{x,i,0/1,j}$ 表示**删去后 $x$ 个字符的串**匹配 KMP 的状态是 $i$,存在/不存在 $0\le y\le x$ 使得加入后 $x$ 个字符中的前 $y$ 个字符后 KMP 状态是 $n$,后 $x$ 个字符作为左端点贡献了总共 $j$ 个区间的可行性。 初始化和转移是简单的,预处理将所有 KMP 状态匹配 $0,1$ 或滚木时沿着 $\operatorname{fail}$ 跳时,被顶掉的状态贡献的区间数即可。时间复杂度 $O(Tnm^2)$,过不去,但是注意到这里是可行性 dp 且有关 $j$ 这一维在转移时涉及到了平移······咳咳······ 时间复杂度 $O(Tnm\times\frac{m}{\omega})$,可以通过。**更多实现细节看代码**。 ```cpp #include<bits/stdc++.h> using namespace std; int cid,T,n,K,kmp[205],mat[205][2],cnt0[205],sum0[205],sum1[205],sum2[205]; string s;bool a[205]; bitset<3005>B[6005][205][2]; int mtch(int x,bool c){ if(x==-1)return 0; if(x<n&&a[x+1]==c)return x+1; return mtch(kmp[x],c); } int main(){ cin.tie(0)->sync_with_stdio(0); cin>>cid>>T; while(T--){ cin>>n>>K>>s;for(int i=1;i<=n;i++)a[i]=(s[i-1]=='1'); kmp[0]=-1;for(int i=1;i<=n;i++)kmp[i]=mtch(kmp[i-1],a[i]); for(int i=0;i<=n;i++){ mat[i][0]=mtch(i,0);mat[i][1]=mtch(i,1); cnt0[i]=sum0[i]=sum1[i]=sum2[i]=0; for(int x=i;x!=-1;x=kmp[x]){ if(x==n){sum0[i]+=n-1;sum1[i]+=n-1;sum2[i]+=n-1;} else{ sum2[i]+=x; if(a[x+1]){cnt0[i]++;sum0[i]+=x;} else sum1[i]+=x; } } } for(int i=0;i<=n;i++)if(sum2[i]<=K)B[0][i][i==n][sum2[i]]=1; bool satis=0;int len=0,ii=0,oo=1,kk=K; for(int r=1;r<=2*K;r++){ for(int i=0;i<=n;i++)for(int o=0;o<2;o++){ if(sum0[i]+cnt0[i]*r<=K)B[r][i][o|(i==n)]|=(B[r-1][mat[i][0]][o]<<(sum0[i]+cnt0[i]*r)); if(sum1[i]<=K)B[r][i][o|(i==n)]|=(B[r-1][mat[i][1]][o]<<sum1[i]); } if(B[r][0][1][K]==1){satis=1;len=r;break;} } if(!satis)cout<<"Impossible\n"; else{ for(int r=len;r>0;r--){ if(ii==n&&oo==1&&sum0[ii]+cnt0[ii]*r<=kk&&B[r-1][mat[ii][0]][0][kk-sum0[ii]-cnt0[ii]*r]==1){ cout<<0;kk-=sum0[ii]+cnt0[ii]*r;ii=mat[ii][0];oo=0; } else if(sum0[ii]+cnt0[ii]*r<=kk&&B[r-1][mat[ii][0]][oo][kk-sum0[ii]-cnt0[ii]*r]==1){ cout<<0;kk-=sum0[ii]+cnt0[ii]*r;ii=mat[ii][0]; } else if(ii==n&&oo==1&&sum1[ii]<=kk&&B[r-1][mat[ii][1]][0][kk-sum1[ii]]==1){ cout<<1;kk-=sum1[ii];ii=mat[ii][1];oo=0; } else if(sum1[ii]<=kk&&B[r-1][mat[ii][1]][oo][kk-sum1[ii]]==1){ cout<<1;kk-=sum1[ii];ii=mat[ii][1]; } } cout<<'\n'; } for(int r=0;r<=2*K;r++)for(int i=0;i<=n;i++)for(int o=0;o<2;o++)B[r][i][o]=0; } return 0; } ```