zoukankan      html  css  js  c++  java
  • AGC024F Simple Subsequence Problem

    Simple Subsequence Problem

    You are given a set (S) of strings consisting of 0 and 1, and an integer (K) .

    Find the longest string that is a subsequence of (K) or more different strings in (S) . If there are multiple strings that satisfy this condition, find the lexicographically smallest such string.

    Here, (S) is given in the format below:

    • The data directly given to you is an integer (N) , and (N+1) strings (X_0,X_1,...,X_N) . For every (i~(0leq ileq N)) , the length of (X_i) is (2^i) .

    • For every pair of two integers ((i,j)~(0leq ileq N,0leq jleq 2^i-1)) , the (j) -th character of (X_i) is 1 if and only if the binary representation of (j) with (i) digits (possibly with leading zeros) belongs to (S) . Here, the first and last characters in (X_i) are called the (0) -th and ((2^i-1)) -th characters, respectively.

    • (S) does not contain a string with length (N+1) or more.

    (Nleq 20).

    题解

    仓鼠《动态规划选讲》。

    因为可能的串(S)并不多,所以考虑对于每个串(S),计数它是多少个集合串的子序列。

    考虑构造出一个类似自动机的东西。

    设一个状态((S, T))表示现在有一个串(S),它后面需要接一个(T)的子序列。

    转移就类似在子序列自动机上走的过程,在它后面添加01可以分别走到两个状态,还有一个转移是不加任何字符然后结束。这样状态就构成了一个DAG。

    同时这个DAG有个很好的性质,因为是用类似子序列自动机的方法构造出来的,所以两点之间路径唯一。

    根据前面的分析,如果(S)(T)的子序列,那么当且仅当((varnothing, T))可以走到((S, varnothing)),这里用(varnothing)表示空串。

    因为路径唯一,所以直接在DAG上做路径计数即可

    因为这个状态满足(|S| + |T| ≤ N),所以状态数是(O(N × 2^N))的。转移(O(1)),时间复杂度也就是(O(N × 2^N))

    这道题的巧妙之处在于,考虑对于每个集合中的串S,让它对它的所有子序列不重不漏产生贡献。暴力只能是对于每个串在子序列自动机上走,但是如果注意到子序列自动机可以压下来,以及后面的一些相关性质,这道题就迎刃而解了。

    代码参考:https://www.cnblogs.com/nealchen/p/AGC024F.html

    为了描述字符串的长度(针对有前导0的那些串),我们在字符串前加一个1来描述字符串的长度。

    #define clz __builtin_clz
    
    char str[(1<<20)+1];
    int*F[1<<21],trans[1<<21][2];
    
    int main(){
    	int n=read<int>(),K=read<int>();
    	F[1]=new int[1<<(n+1)];
    	F[1][0]=0;
    	for(int i=0;i<=n;++i){
    		int p=1<<i;
    		scanf("%s",str);
    		for(int j=0;j<p;++j) F[1][p+j]=str[j]-'0'; // use a leading 1 to describe the length
    		for(int j=0;j<p;++j) trans[p+j][1]=j;
    		trans[2*p-1][0]=0; // doesn't exist
    		for(int j=1;j<p;++j) trans[2*p-1-j][0]=j^((1<<(31-clz(j)))-1);
    	}
    	int ans=1;
    	for(int i=1;i<=n;++i){
    		int p=1<<i;
    		for(int j=2*p-1;j>=p;--j){
    			F[j]=new int[1<<(n-i+1)];
    			memset(F[j],0,sizeof(int)<<(n-i+1));
    			for(int k=1;k<1<<(n-i+2);++k) F[j][trans[k][j&1]]+=F[j>>1][k];
    			F[j][0]=0;
    			if(accumulate(F[j],F[j]+(1<<(n-i+1)),0)>=K) ans=j;
    		}
    	}
    	for(int i=31-clz(ans)-1;i>=0;--i) printf("%d",ans>>i&1);
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    luogu1197 [JSOI2008]星球大战
    luogu2085 最小函数值
    Vijos 1144 小胖守皇宫 【树形DP】
    洛谷 P1941 飞扬的小鸟 【DP+众多特判】
    codevs 1516 平均分数 【数学推理+求逆序对】
    tyvj 1936 太空战队 【强连通分量】
    USACO 2.4 Overfencing 【种子染色法+递推】
    code[vs] 2488 绿豆蛙的归宿【反向拓扑+DP】
    USACO 2.3 Zero Sum 【搜索+字符串处理+模拟计算】
    USACO 2.3 Cow Pedigrees 【DP+前缀和优化】
  • 原文地址:https://www.cnblogs.com/autoint/p/12695621.html
Copyright © 2011-2022 走看看