agc024F Simple Subsequence Problem
-
给若干个01串,求一个最长的01串使得它是至少 m m m个给出01串的子序列。
-
在长度最长的情况下求输出字典序最小的01串。
-
∣ s ∣ ≤ 20 |s|\le20 ∣s∣≤20.
Solution
- 感觉这种题目就没有什么性质,只能暴力了。
- 问题是怎么暴力。
- 不妨考虑前面已经枚举了一个子序列,那么对于所有串尽可能地匹配,一开始我想记每一个串匹配到的位置,但是由于值域很小,只有 2 20 2^{20} 220,我们可以状压后面剩下的串!
- 那么记 f [ S ] [ T ] f[S][T] f[S][T]表示前面已经枚举的子序列是 S S S,匹配这个子序列剩下 T T T的有 f [ S ] [ T ] f[S][T] f[S][T]个。
- 直接枚举下一个选择 0 / 1 0/1 0/1转移即可。
- 状态数是 2 n n 2^nn 2nn的,时空复杂度 O ( 2 n n ) O(2^nn) O(2nn)
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxn 21
using namespace std;
int n,m,i,j,k,l,ans,anslen;
int f[2][maxn][1<<maxn],nx[2][maxn][1<<maxn];
int main(){
freopen("ceshi.in","r",stdin);
scanf("%d%d",&n,&m); char ch=getchar();
for(i=0;i<=n;i++){
while (ch<'0'||ch>'1') ch=getchar();
for(j=0;j<1<<i;j++) f[0][i][j]=ch-'0',ch=getchar();
}
for(i=0;i<n;i++) for(j=0;j<1<<i;j++) for(k=0;k<2;k++) for(int t=0;t<2;t++){
if (k==t) nx[t][i+1][j|(k<<i)]=i+1;
else nx[t][i+1][j|(k<<i)]=nx[t][i][j];
}
for(i=0;i<=n;i++){
int p=i&1,q=p^1;
for(j=0;j<1<<i;j++){
int s=0;
for(k=0;i+k<=n;k++) for(int S=0;S<1<<k;S++) if (f[p][k][j<<k|S])
s+=f[p][k][j<<k|S];
if (s>=m&&i>anslen) ans=j,anslen=i;
}
if (i==n) break;
for(j=0;i+1+j<=n;j++) memset(f[q][j],0,sizeof(int)*((1<<i+j+1)+1));
for(j=1;i+j<=n;j++) for(k=0;k<1<<i+j;k++) if (f[p][j][k]){
int S=k^(k>>j<<j);
for(int t=0;t<2;t++) if (nx[t][j][S]) {
l=nx[t][j][S]-1;
f[q][l][(k>>j<<1^t)<<l|(S^(S>>l<<l))]+=f[p][j][k];
}
}
}
for(i=anslen;i>=1;i--) putchar('0'+(ans>>i-1&1));
}