ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[atAGC046E]Permutation Cover

2020-12-16 08:35:20  阅读:202  来源: 互联网

标签:排列 包含 int Cover atAGC046E 插入 le 2a Permutation


每一个点都在一个排列中等价于所有排列覆盖所有位置

有解当且仅当满足$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 } 
View Code

 

标签:排列,包含,int,Cover,atAGC046E,插入,le,2a,Permutation
来源: https://www.cnblogs.com/PYWBKTDA/p/14141985.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有