agc046_e Permutation Cover

agc046_e Permutation Cover

https://atcoder.jp/contests/agc046/tasks/agc046_e

UK4Akq.png

Tutorial

https://img.atcoder.jp/agc046/editorial.pdf

称序列中每个元素都在某个作为排列的区间中为性质1

考虑什么时候才有解.

对于单独两个元素(a_x,a_y)分析,若(a_x>2a_y),那么发现一定存在某个(x),距离左右的边界(x)之间都没有(y).

也就是说对于最大值(a_x)和最小值(a_y),(a_x le 2a_y)是有解的必要条件.

考虑如果满足这个条件如何构造一组解,发现对于任意(Sin[K]),一定存在一种序列使得(S)中的元素出现了二次,([K]setminus S)的元素出现了一次,且满足性质1.那么就可以这样分为若干组以上面的条件为指导构造出一组解来.

所以(a_x le 2a_y)是有解的充要条件.

考虑贪心的增量构造,设现在的序列为(P),且(|P|ge K),满足性质1.考虑怎样的(P)是合法(即可以成为某个解的前缀)的.

和上面类似的考虑,设(b_i)表示剩下的序列中还需要(i)出现多少次,而且由于(P)的存在相当于左边界的条件有所改变,所以

  • (x,y)分别为(b)的最大值和最小值,则(xle 2y+1)
  • (x=2y+1),则(P)的结尾的(K)个元素,称其为排列(Q),满足所有(b_i=x)的元素在(b_i=y)的元素之前

证明必要和充分的过程和上面类似.

此时由于我们需要(P)时刻满足性质1,所以不能像一般增量法一样一个个添加元素.我们枚举添加的元素个数(m),我们要添加的元素要和(P)结尾的(K-m)个元素组成排列,且需要满足上述(P)合法的条件.对于每个(m),我们可以贪心得到字典序最小的增加的元素的排列或判断其无解.然后对于合法的所有排列,选择字典序最小的加入(P).

对于每个(m),贪心的复杂度是(O(K)),总时间复杂度(O(K^2 sum a_i))

Code

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
inline char gc() {
	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
	x=0; int f=1,ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
	x*=f;
}
const int maxK=100+5,maxn=1000+5;
int n,K,a[maxK],an[maxn];
bool vis[maxK];
inline bool cmp(const vector<int> &a,const vector<int> &b) {
	for(int i=0;i<a.size()&&i<b.size();++i) if(a[i]!=b[i]) return a[i]<b[i];
	return a.size()<b.size();
}
void fail(vector<int> &re) {
	for(int i=0;i<=K;++i) re.push_back(K+1);
}
void sol(int s,int m,vector<int> &re) {
	static int b[maxK]; memcpy(b,a,sizeof(b));
	memset(vis,0,sizeof(vis));
	for(int i=1;i+m<=K;++i) vis[an[s-i]]=1;
	for(int i=1;i<=K;++i) if(!vis[i]) {
		if(!b[i]) {fail(re); return;}
		--b[i];
	}
	int x=*max_element(b+1,b+K+1),y=*min_element(b+1,b+K+1);
	if(x>2*y+1) {fail(re); return;}
	vector<int> A,B,C;
	if(x==2*y+1) {
		bool flag=0;
		for(int i=1;i+m<=K;++i) {
			if(b[an[s-i]]==x) flag=1;
			else if(b[an[s-i]]==y) {
				if(flag) {fail(re); return;}
			}
		}
		for(int i=K;i>=1;--i) if(!vis[i]) {
			if(b[i]==x) A.push_back(i);
			else if(b[i]==y) B.push_back(i);
			else C.push_back(i);
		}
	}
	else for(int i=K;i>=1;--i) if(!vis[i]) C.push_back(i);
	for(int i=1;i<=m;++i) {
		if(A.size()) {
			int t=C.size()?C.back():K+1;
			if(A.back()<t) re.push_back(A.back()),A.pop_back();
			else re.push_back(t),C.pop_back();
		}
		else {
			int a=B.size()?B.back():K+1,b=C.size()?C.back():K+1;
			if(a<b) re.push_back(a),B.pop_back();
			else re.push_back(b),C.pop_back();
		}
	}
}
int main() {
	rd(K);
	for(int i=1;i<=K;++i) rd(a[i]),n+=a[i];
	if(*max_element(a+1,a+K+1)>2*(*min_element(a+1,a+K+1))) {puts("-1"); return 0;}
	for(int i=1;i<=n;) {
//		debug("---
");
		vector<int> Q[maxK];
		if(i==1) sol(i,K,Q[1]);
		else {
			for(int j=1;j<=K;++j) sol(i,j,Q[j]);
			int k=1;
			for(int j=2;j<=K;++j) if(cmp(Q[j],Q[k])) k=j;
			if(k!=1) swap(Q[1],Q[k]);
		}
		for(int j=0;j<Q[1].size();++j) an[i+j]=Q[1][j],--a[Q[1][j]];
		i+=Q[1].size();
//		for(int j=1;j<i;++j) debug("%d ",an[j]); debug("
");
	}
	for(int i=1;i<=n;++i) {
		if(i!=1) printf(" ");
		printf("%d",an[i]);
	}
	printf("
");
	return 0;
}
原文地址:https://www.cnblogs.com/ljzalc1022/p/13280190.html