agc024F Simple Subsequence Problem

agc024F Simple Subsequence Problem

  • 给若干个01串,求一个最长的01串使得它是至少 m m m个给出01串的子序列。

  • 在长度最长的情况下求输出字典序最小的01串。

  • ∣ s ∣ ≤ 20 |s|\le20 s20.

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
#include
#include
#include
#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));
}

你可能感兴趣的:(atcoder,DP,状态压缩,agc024F,DP,状压)