[AGC046E] Permutation Cover 题解

神秘构造题,需要一定的积累。

看到最小排列,我们优先考虑构造一个合法排列,假设\(a_x\)最大,\(a_y\)最小,如果说\(a_x>2a_y\)那么一定无解(考虑一个\(y\)最多和两个\(x\)匹配),然后当\(a_x \le 2a_y\)的时候,我们发现一定有解(归纳法证明,只需要考虑\(x,y\),出现次数比\(y\)多的如果不可以\(y\)一定不可以,\(y\)的限制因为出现次数少所以更大。)

然后考虑迭代证明,我们现在取出一个长度为\(len\)的数字串,如果说把这个串按某种顺序排列后接到答案序列的末尾,余下的数字中\(x\)使得\(a_x\) 最大,\(y\)使得\(a_y\)最小。
1.\(a_x<=2a_y\)后续一定有解,这个数字串直接按字典序最小排列即可。
2.\(a_x>2a_y+1\)后续一定无解,不用考虑。
3.\(a_x==2a_y+1\)我们发现,只要任意符合条件的\(x,y\),满足\(x\)一定在\(y\)的前头,随意贪心即可。(这个时候一定可以在后缀加上一个有\(x\)没有\(y\)的串,然后就变成第一种情况了,一定有解,只要这种序列的字典序最小就可以直接贪心选择。)

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1010;
int n,a[maxn],mn,mx,sum,vis[maxn],lst,aa[maxn];
struct edge{
	int len;
	int a[maxn];
}ans,bu,st,ss;
int cmp(int q,int w){
	return a[q]<a[w];
}
void push(edge q){
	for(int i=1;i<=min(q.len,bu.len);i++){
		if(q.a[i]<bu.a[i]){
			bu=q;
			return;
		}
		if(q.a[i]>bu.a[i]){
			return;
		}
	}
	if(q.len<bu.len){
		bu=q;
	}
	return;
}
void check(int len){
	for(int i=1;i<=n;i++){
		vis[i]=0;
	}
	for(int i=ans.len-(n-len)+1;i<=ans.len;i++){
		vis[ans.a[i]]=1;
	}
	st.len=0;
	mx=0;
	mn=1e9;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			st.len++;
			st.a[st.len]=i;
			a[i]--;
		}
		mx=max(mx,a[i]);
		mn=min(mn,a[i]);
	}
	if(mx>2*mn+1){
		return;
	}
	if(mx<=2*mn){
		push(st);
		return;
	}
	ss.len=0;
	lst=0;
	for(int i=1;i<=st.len;i++){
		if(a[st.a[i]]==mx){
			lst=i;
		}
	}
	for(int i=1;i<=st.len;i++){
		if(i>lst||a[st.a[i]]!=mn){
			ss.len++;
			ss.a[ss.len]=st.a[i];
		}
		if(i==lst){
			for(int j=1;j<=i;j++){
				if(a[st.a[j]]==mn){
					ss.len++;
					ss.a[ss.len]=st.a[j];
				}
			}
		}
	}
	push(ss);
	return;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	mn=1e9;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];
		mn=min(mn,a[i]);
		mx=max(mx,a[i]);
	}
	if(2*mn<mx){
		cout<<"-1";
		return 0;
	}
	bu.len=1;
	bu.a[1]=n+1;
	for(int j=1;j<=n;j++){
		aa[j]=a[j];
	}
	check(n);
	for(int j=1;j<=n;j++){
		a[j]=aa[j];
	}
	ans=bu;
	for(int i=1;i<=ans.len;i++){
		a[ans.a[i]]--;
	}
	while(ans.len!=sum){
		bu.len=1;
		bu.a[1]=n+1;
		for(int i=1;i<=n&&i+ans.len<=sum;i++){
			for(int j=1;j<=n;j++){
				aa[j]=a[j];
			}
			check(i);
			for(int j=1;j<=n;j++){
				a[j]=aa[j];
			}
		}
		for(int i=1;i<=bu.len;i++){
			ans.len++;
			ans.a[ans.len]=bu.a[i];
			a[bu.a[i]]--;
		}
	}
	for(int i=1;i<=ans.len;i++){
		cout<<ans.a[i]<<' ';
	}
	return 0;
}
```* 
posted @ 2025-06-21 09:26  特别之处  阅读(13)  评论(0)    收藏  举报