[atAGC046E]Permutation Cover
每一个点都在一个排列中等价于所有排列覆盖所有位置
有解当且仅当满足$a_{y}\le 2a_{x}$(其中$a_{x}$为$a_{i}$的最小值,$a_{y}$为$a_{i}$的最大值)
证明:贪心选择排列覆盖,即令$r'=与[1,r]有交的排列中最大的右端点+1$(初始$r=1$,若$r=r'$则不合法),令以此法选出的排列总数为$s$,以下证明$a_{y}\le s\le 2a_{x}$
对于每一个$p_{i}=x$,包含$i$的排列最多有两个,那么包含$x$的排列数最多为$2x$,同时一个排列必然包含$x$,即可得$s=包含x的排列数\le 2a_{x}$
对于每一个$p_{i}=y$,包含$i$的排列至少有1个,类似的即$s=包含y的排列数\ge a_{y}$
反过来,这个条件也是充分的,考虑通过以下方法构造合法解:
若$a_{x}=a_{y}$,将$\{1,2,...,n\}$重复写$a_{x}$次即可
若$a_{x}<a_{y}$,不断放两个相交的排列,交为所有$a_{t}=a_{x}$的$t$(即其余数都出现2次,这些数重复,仅出现1次),由于初始$a_{y}\le 2a_{x}$,因此最终会有$a_{x}=a_{y}\ge 0$,再用第1种方法即可
接下来,构造字典序最小的解——
考虑增量法,每一次插入一段使得后缀是一个排列,贪心要求插入字典序最小的段,问题即变为判定插入后是否合法
(若字典序比较为前缀关系取较短的串即可,因为可以将后面多出的一部分可以放在下一段中调整)
令插入后的每一个数还需要出现的次数为$a_{i}$,仍然对$a_{x}$和$a_{y}$讨论:
1.若$a_{y}\le 2a_{x}$,一定可行;若$a_{y}>2a_{x}+1$,一定不可行
2.若$a_{y}=2a_{x}+1$,可以将末尾这个排列看成我们构造合法解中两个排列的前半个,那么我们相当于要让其能够与后一个交上$a_{t}=a_{x}$的部分但不交$a_{t}=a_{y}$的部分
由于下一个排列也是任意的,因此即要求$a_{t}=a_{x}$的位置都在$a_{t}=a_{y}$的位置之后
这个条件的必要性也狠显然,因为如果不满足,类似于上面对$s$范围进行分析即可发现矛盾
考虑枚举插入段的长度,根据原来$p_{i}$的后缀就可以确定插入后的$a_{i}$,顺序再通过上面的结论贪心即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 vector<int>oo,v,ans; 5 int n,L,l,a[N],b[N],vis[N],p[N]; 6 int get_min(){ 7 int ans=a[1]; 8 for(int i=2;i<=n;i++)ans=min(ans,a[i]); 9 return ans; 10 } 11 int get_max(){ 12 int ans=a[1]; 13 for(int i=2;i<=n;i++)ans=max(ans,a[i]); 14 return ans; 15 } 16 void min_zdx(vector<int>&x,vector<int>y){ 17 for(int i=0;i<min(x.size(),y.size());i++) 18 if (x[i]!=y[i]){ 19 if (x[i]>y[i])x=y; 20 return; 21 } 22 if (x.size()>y.size())x=y; 23 } 24 void get_nex(int k){ 25 v.clear(); 26 if ((l+k<n)||(l+k>L)){ 27 v=oo; 28 return; 29 } 30 memset(vis,0,sizeof(vis)); 31 for(int i=l+k-n+1;i<=l;i++)vis[p[i]]=1; 32 for(int i=1;i<=n;i++) 33 if (!vis[i]){ 34 v.push_back(i); 35 a[i]--; 36 } 37 int x=get_min(),y=get_max(); 38 if (2*x>=y)return; 39 if (2*x+1<y){ 40 v=oo; 41 return; 42 } 43 int las=0; 44 for(int i=0;i<v.size();i++) 45 if (a[v[i]]==y)las=i; 46 vector<int>vv,vx; 47 for(int i=0;i<v.size();i++){ 48 if ((i>las)||(a[v[i]]!=x))vv.push_back(v[i]); 49 else vx.push_back(v[i]); 50 if (i==las) 51 for(int j=0;j<vx.size();j++)vv.push_back(vx[j]); 52 } 53 v=vv; 54 } 55 int main(){ 56 scanf("%d",&n); 57 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 58 if (2*get_min()<get_max()){ 59 printf("-1"); 60 return 0; 61 } 62 for(int i=1;i<=n;i++)L+=a[i]; 63 oo.push_back(n+1); 64 while (l<L){ 65 ans=oo; 66 for(int i=1;i<=n;i++){ 67 memcpy(b,a,sizeof(a)); 68 get_nex(i); 69 memcpy(a,b,sizeof(b)); 70 min_zdx(ans,v); 71 } 72 for(int i=0;i<ans.size();i++){ 73 p[++l]=ans[i]; 74 a[ans[i]]--; 75 } 76 } 77 for(int i=1;i<=l;i++)printf("%d ",p[i]); 78 }