[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;
}
```*
浙公网安备 33010602011771号