zoukankan      html  css  js  c++  java
  • AtCoder AGC024F Simple Subsequence Problem (字符串、DP)

    题目链接

    https://atcoder.jp/contests/agc024/tasks/agc024_f

    题解

    考虑对每个串都求出它是几个给定的串的子序列。
    (O(4^n)) 暴力的基础上考虑优化,状态可以进行如下的压缩:用有序 01 字符串对 ((S,T)) 代表当前已有字符串 (S), 后面还需要加字符串 (T). 转移就枚举下一个选的是什么即可。
    可以发现转移是一个DAG,并且每条路径对应的字符串不同。因此直接在DAG上进行路径计数即可。
    时间复杂度 (O(2^nn)).

    代码

    #include<bits/stdc++.h>
    #define llong long long
    #define mkpr make_pair
    #define riterator reverse_iterator
    using namespace std;
    
    inline int read()
    {
    	int x = 0,f = 1; char ch = getchar();
    	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
    	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
    	return x*f;
    }
    
    const int N = 20;
    char a[(1<<N+1)+3];
    int f[(1<<N+1)+3][N+3];
    int bitcnt[(1<<N+1)+3],lg2[(1<<N+1)+3];
    int nxt[(1<<N+1)+3][2],cnt[(1<<N+1)+3];
    int n,m;
    
    int main()
    {
    	for(int i=1; i<(1<<N+1); i++) bitcnt[i] = bitcnt[i>>1]+(i&1);
    	lg2[1] = 0; for(int i=2; i<(1<<N+1); i++) lg2[i] = lg2[i>>1]+1;
    	scanf("%d%d",&n,&m);
    	for(int i=0; i<=n; i++)
    	{
    		scanf("%s",a); for(int j=0; j<(1<<i); j++) f[j|(1<<i)][0] = a[j]-48;
    	}
    	for(int i=1; i<(1<<n+1); i++)
    	{
    		int len = lg2[i]; int sta = i^(1<<len);
    		for(int x=0; x<2; x++)
    		{
    			nxt[i][x] = -1;
    			for(int j=len-1; j>=0; j--)
    			{
    				if(((i>>j)&1)==x) {nxt[i][x] = (i&((1<<j)-1))|(1<<j); break;}
    			}
    //			printf("nxt[%d][%d]=%d
    ",i,x,nxt[i][x]);
    		}
    	}
    	for(int j=0; j<=n; j++)
    	{
    		for(int i=(1<<j); i<(1<<n+1); i++)
    		{
    			int len = lg2[i]; int sta = i^(1<<len);
    			if(f[i][j]==0) continue;
    			cnt[i>>len-j] += f[i][j];
    			for(int x=0; x<2; x++)
    			{
    				if(nxt[(sta&((1<<len-j)-1))|(1<<len-j)][x]==-1) continue;
    				int sta2 = nxt[(sta&((1<<len-j)-1))|(1<<len-j)][x],len2 = lg2[sta2]; sta2 ^= (1<<len2);
    				sta2 |= (((i>>len-j)<<1|x)<<len2);
    //				printf("(%d,%d)+%d->(%d,%d)
    ",i,j,x,sta2,j+1);
    				f[sta2][j+1] += f[i][j];
    			}
    		}
    	}
    	int ans = 0;
    	for(int i=1; i<(1<<n+1); i++)
    	{
    //		printf("cnt[%d]=%d
    ",i,cnt[i]);
    		if(cnt[i]>=m)
    		{
    			if(lg2[i]>lg2[ans]||(lg2[i]==lg2[ans]&&i<ans)) {ans = i;}
    		}
    	}
    	int len = lg2[ans]; for(int i=len-1; i>=0; i--) printf("%d",(ans>>i)&1); puts("");
    	return 0;
    }
    
  • 相关阅读:
    windows下命令行
    利用border画三角形
    正则
    flex布局
    css笔记
    W3C标准
    SEO相关
    左边固定,右边自适应(解决方案)
    容错性测试的测试点
    Charles安装及使用教程
  • 原文地址:https://www.cnblogs.com/suncongbo/p/12534603.html
Copyright © 2011-2022 走看看