zoukankan      html  css  js  c++  java
  • Gym 101239E BZOJ 4110 [CERC2013]Evolution in Parallel (DP、结论)

    题目链接

    (Gym) https://codeforces.com/gym/101239
    (BZOJ) 大人,时代变了。

    题解

    这题好神仙啊
    首先有一个显然的 DP,按长度从小到大排序,维护一下目前可选的方案中除了 (i) 所在的组之外的组的最后一个元素都有哪些可能性。在 (O(L)) 时间内判断一个串是否是另一个的子序列,时间复杂度 (O(n^2L)).
    但是这样并不能过,有一个很神仙的结论是,任何一个时刻有用的可选的方案只有至多 (2) 种,特别地,如果有 (2) 种,设为 ((i-1,x))((i-1,y)) 则一定满足 (x)(y) 都是 ((i-1)) 的子序列。
    这可以用数学归纳法证明。最一开始显然只有一种可选方案。
    如果某一时刻只有一种可选方案(不妨设为 ((i-1,x))),那么下一个时刻只有可能出现 ((i,x))((i,i-1)) 这两种。如果两种都出现,那么显然满足 ((i-1))(x) 都是 (i) 的子序列。
    如果某一时刻有两种可选方案且满足上述条件(不妨设为 ((i-1,x))((i-1,y))):
    如果 ((i-1))(i) 的子序列,那么 ((i,x))((i,y)) 都会成为候选集合,且 (x)(y) 都是 (i) 的子序列。这时 ((i,i-1)) 还有可能成为候选集合,但是我们注意到如果 ((i,i-1)) 成为了候选集合,那么因为 (x)(y) 都是 ((i-1)) 的子序列,即 ((i,i-1)) 可以被 ((i,x))((i,y)) 完全替代!所以我们可以舍弃 ((i,i-1)) 这种可能性,可选集合最多还是只有 (2) 个。
    否则,可选集合只可能有 ((i,i-1)) 这一种。
    所以转移就可以了,时间复杂度 (O(nL)).

    代码

    #include<bits/stdc++.h>
    #define llong long long
    #define mkpr make_pair
    #define x first
    #define y second
    #define iter iterator
    #define riter reverse_iterator
    #define y1 Lorem_ipsum_
    #define tm dolor_sit_amet_
    #define pii pair<int,int>
    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 mxN = 4000;
    int n;
    string a[mxN+3];
    vector<pii> s[mxN+3];
    vector<int> ans[2];
    
    bool cmp_len(string s,string t) {return s.length()<t.length();}
    
    bool judge(int u,int v)
    {
    	for(int i=0,j=0; i<a[u].length(); i++)
    	{
    		while(j<a[v].length()&&a[v][j]!=a[u][i]) {j++;}
    		if(j==a[v].length()) {return false;} j++;
    	}
    	return true;
    }
    
    int main()
    {
    	n = read(); cin>>a[n+1];
    	for(int i=1; i<=n; i++) cin>>a[i];
    	sort(a+1,a+n+1,cmp_len);
    	for(int i=1; i<=n; i++) if(!judge(i,n+1)) {puts("impossible"); return 0;}
    	s[0].push_back(mkpr(0,0));
    	for(int i=1; i<=n; i++)
    	{
    		if(s[i-1].size()==1)
    		{
    			if(judge(i-1,i)) {s[i].push_back(mkpr(s[i-1][0].x,i-1));}
    			if(i-1!=s[i-1][0].x&&judge(s[i-1][0].x,i)) {s[i].push_back(mkpr(i-1,s[i-1][0].x));}
    		}
    		else if(s[i-1].size()==2)
    		{
    			if(judge(i-1,i)) {s[i].push_back(mkpr(s[i-1][0].x,i-1)); s[i].push_back(mkpr(s[i-1][1].x,i-1));}
    			else if(judge(s[i-1][0].x,i)) {s[i].push_back(mkpr(i-1,s[i-1][0].x));}
    			else if(judge(s[i-1][1].x,i)) {s[i].push_back(mkpr(i-1,s[i-1][1].x));}
    		}
    		if(!s[i].size()) {puts("impossible"); return 0;}
    	}
    	for(int i=n,j=s[n][0].x,x=0; i>=1; i--)
    	{
    		ans[x].push_back(i);
    		for(int k=0; k<s[i].size(); k++) if(s[i][k].x==j)
    		{
    			if(s[i][k].x==i-1) {x^=1; j = s[i][k].y;}
    			else {j = s[i][k].x;}
    			break;
    		}
    	}
    	printf("%d %d
    ",ans[0].size(),ans[1].size());
    	for(int i=ans[0].size(); i>=1; i--) cout<<a[ans[0][i-1]]<<endl;
    	for(int i=ans[1].size(); i>=1; i--) cout<<a[ans[1][i-1]]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    深入探索迭代器(续)
    深入探索迭代器
    C++ 容器的综合应用的一个简单实例——文本查询程序
    multimap 和 multiset 类型
    set 类型
    map 类型
    关联容器
    Ajax请求成功, 但进不去success方法
    springboot指定配置文件启动项目
    新测可用IntelliJ IDEA 2020.1 for mac
  • 原文地址:https://www.cnblogs.com/suncongbo/p/14265862.html
Copyright © 2011-2022 走看看