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

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

[atAGC046E]Permutation Cover的更多相关文章

  1. Dancing Links and Exact Cover

    1. Exact Cover Problem DLX是用来解决精确覆盖问题行之有效的算法. 在讲解DLX之前,我们先了解一下什么是精确覆盖问题(Exact Cover Problem)? 1.1 Po ...

  2. Permutation Sequence

    The set [1,2,3,-,n] contains a total of n! unique permutations. By listing and labeling all of the p ...

  3. [LeetCode] Palindrome Permutation II 回文全排列之二

    Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empt ...

  4. [LeetCode] Palindrome Permutation 回文全排列

    Given a string, determine if a permutation of the string could form a palindrome. For example," ...

  5. [LeetCode] Permutation Sequence 序列排序

    The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the p ...

  6. [LeetCode] Next Permutation 下一个排列

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

  7. Leetcode 60. Permutation Sequence

    The set [1,2,3,-,n] contains a total of n! unique permutations. By listing and labeling all of the p ...

  8. img及父元素(容器)实现类似css3中的background-size:contain / background-size:cover

    img及父元素(容器)实现类似css3中的background-size:contain / background-size:cover <!DOCTYPE html> <html ...

  9. UVA11525 Permutation[康托展开 树状数组求第k小值]

    UVA - 11525 Permutation 题意:输出1~n的所有排列,字典序大小第∑k1Si∗(K−i)!个 学了好多知识 1.康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+ ...

随机推荐

  1. 实时获取股票数据,免费!——Python爬虫Sina Stock实战

    更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流. 实时股票数据的重要性 对于四大可交易资产:股票.期货.期权.数字货币来说,期货.期权.数字货币,可以从交 ...

  2. 分布式/微服务必配APM系统,SkyWalking让你不迷路

    前言 如今分布式.微服务盛行,面对拆分服务比较多的系统,如果线上出现异常,需要快速定位到异常服务节点,假如还用传统的方式排查肯定效率是极低的,因为服务之间的各种通信会让定位更加繁琐:所以就急需一个分布 ...

  3. 无法获取指向控制台的文件描述符 (couldn't get a file descriptor referring to the console)

    背景 最近收拾东西,从一堆杂物里翻出来尘封四年多的树莓派 3B 主机来,打扫打扫灰尘,接上电源,居然还能通过之前设置好的 VNC 连上.欣慰之余,开始 clone 我的 git 项目,为它们拓展一个新 ...

  4. Java(6)流程控制语句中分支结构if与switch

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201528.html 博客主页:https://www.cnblogs.com/testero ...

  5. CentOS 用户与群组

    目录 1.用户管理 1.1.切换用户 1.2.添加用户 1.3.删除用户 1.4.修改用户 2.群组管理 2.1.查看群组 2.2.添加群组 2.3.删除群组 2.4.修改群组 1.用户管理 Linu ...

  6. VS2019 及 Visual Assist X 安装配置

    Visual Studio 2019 安装 下载 https://visualstudio.microsoft.com/zh-hans/downloads/ 安装 设置 扩大 Solution Con ...

  7. Codeforces1514B

    问题描述 给你两个数n,k,问可以构造多少n个最大位数为k数按位与为0并且这n个数加起来最大的合法序列,答案对1e9 + 7取模. 思路分析 首先我们考虑这n个数按位与以后为0这个条件:我们可以知道, ...

  8. Java版流媒体编解码和图像处理(JavaCPP+FFmpeg)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. Noip模拟66 2021.10.2

    T1 接力比赛 思路就是直接做背包$dp$,然后看看容量相同的相加的最大值. 考虑如何在$dp$过程中进行优化 注意到转移方程的第二维枚举容量没有必要从容量总和开始枚举 那么我们便转移边统计前缀和,从 ...

  10. 计算机网络之IPv4(IPv4分组、IPv4地址、NAT、子网划分与子网掩码、CIDR、ARP协议、DHCP、ICMP)

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/105138313 学习课程:<2019王道考研计算机网络> 学习目的 ...