「eJOI2022」LCS of Permutations 题解
题意
给定 \(n,a,b,c\),构造大小为 \(n\) 的排列 \(p,q,r\) 满足 \(\operatorname{LCS}(p,q)=a,\operatorname{LCS}(p,r)=b,\operatorname{LCS}(q,r)=c\)。
判断是否有解,可能要求构造方案。多组询问,\(\sum n\le 2\times10^5\)。
题解
Anton 的神题就别考虑正解了。既然是 OI 题,那先去看部分分。
Subtask3 \(c=n\)
排列 \(q,r\) 是一样的,即构造两个 \(\operatorname{LCS}=a\) 的排列。
将 \(p\) 钦定成 \(1,2,\cdots,n\) 不影响答案。之后所有解法也这样考虑。
\(\operatorname{LIS}=a\) 的排列随便构造一下。
Subtask4 \(a=1\)
把 \(q\) 钦定成 \(n,n-1,\cdots,1\)。
要求 \(r\) 的 \(\operatorname{LIS}=b,\operatorname{LDS}=c\)。
显然需要 \(b+c\le n+1\)。
根据 Dilworth 定理,排列最多取成长为 \(c\) 的 \(b\) 条反链,于是 \(bc\ge n\)。
这也是充要条件。构造是简单的。
Subtask5 \(output=0\)
这提示我们判断是否有解的结论是很好猜的。
观察一下 \(a=1\) 时的限制: \(b+c\le n+1,bc\le n\)。
把 \(a\) 硬凑进去,\(b+c\le n+a,abc\le n\)。
实际上这就是正确的结论。先证明一下必要性:
考虑反证,假设 \(abc<n\):
\(\operatorname{LIS}(r)\le b\)
\(\operatorname{LIS}(q)=a\Rightarrow\operatorname{LDS}(q)\ge\frac{n}{a}\ge bc+1\)
\(\operatorname{LDS}(r)\le c\),否则任取出 \(q\) 一个长为 \(bc+1\) 的下降子序列会使得 \(\operatorname{LCS}(q,r)>c\)。
考虑排列 \(r\),根据 Dilworth 定理有 \(bc\ge n\),矛盾。得证。
接下来用构造证明充分性。
正解(方案构造)
先不考虑 corner case,从 \(n=abc\) 这种细节较少的情况想起。
给出构造方案:
\(p=[1,2,\cdots,n]\)
\(q=[|n-a+1,n-a+2,\cdots,n|,|n-2a+1,n-2a+2,\cdots,n-a|,\cdots,|1,2,\cdots,a|]\)(\(bc\) 个递减的长为 \(a\) 的递增块)
\(r=[|ac,ac-1,\cdots,1|,|2ac,2ac-1,\cdots,ac+1|,\cdots,|n,n-1,\cdots,n-ac+1|]\)(\(b\) 个递增的长为 \(ac\) 的递减块)
\(\operatorname{LCS}(p,q)=a,\operatorname{LCS}(p,r)=b\) 都是显然的。
证明 \(\operatorname{LCS}(q,r)=c\):
首先有长为 \(c\) 的公共子序列 \((a-1)c+1,(a-2)c+1,\cdots,1\)。
其次一定有 \(q,r\) 的公共子序列是递减的。在 \(q\) 中只有在同一个大小为 \(a\) 的块中能递增,\(r\) 中仍属于同一个块,要求递减。
于是只能在 \(r\) 中一个递减块中选,并且每 \(a\) 个在 \(q\) 中要求递增了,于是最多选 \(c\) 个。
这个构造必需的数是两两的公共子序列:\([1,2,\cdots,a],[1,ac+1,2ac+1,\cdots,(b-1)ac+1],[(a-1)c+1,(a-2)c+1,\cdots,1]\)。
可以推广到所有 \(a+b+c-2\le n\) 的情况。具体只选择必需的数,不够再一直随便加数。
还剩下 \((a-1)+(b-1)+(c-1)\ge n\) 的情况需要讨论:
如果 \((n-1,a-1,b-1,c-1)\) 是合法的,在每个排列后面加入一个 \(n\) 就可以了。
所有 \((a-1)(b-1)(c-1)<n-1\) 的情况也被解决了。
把限制整理为 \(xyz\le x+y+z-2(x\le y\le z)\)。
当 \(x>1\),有 \(xyz\ge4z>x+y+z>x+y+z+2\),于是 \(x=1\),代回原式为 \(yz\le y+z-1\)。
当 \(y>1\),有 \(yz\ge2z\ge y+z>y+z-1\),于是 \(y=1\)。
由 \(a\le b\le c\),有 \(a=2,b=2\)。代回限制得到 \(c=n-1\)。
这种情况的构造很简单:\(p=[1,2,\cdots,n],q=[n,n-1,\cdots,4,3,1,2],r=[n,n-1,\cdots,4,1,3,2]\)。
完工了。
代码
实现时可以用 set 来维护每个排列元素的顺序。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
vector<int> p,q,r;
bool solve(int n,int a,int b,int c){
if(b+c>a+n||1ll*a*b*c<n) return 0;
if(!n) return 1;
if(solve(n-1,a-1,b-1,c-1)){
p.push_back(n);q.push_back(n);r.push_back(n);
return 1;
}
if(a+b+c-2>n){
for(int i=1;i<=n;i++) p.push_back(i);
for(int i=1;i<=n-3;i++) q.push_back(n-i+1),r.push_back(n-i+1);
q.insert(q.end(),{3,1,2});
r.insert(r.end(),{1,3,2});
return 1;
}
set<ll> sp;
auto posq=[&](ll x) {return make_pair(-(x-1)/a,x);};
auto cmpq=[&](ll x,ll y) {return posq(x)<posq(y);};
set<ll,decltype(cmpq)> sq(cmpq);
auto posr=[&](ll x) {return make_pair((x-1)/a/c,-x);};
auto cmpr=[&](ll x,ll y) {return posr(x)<posr(y);};
set<ll,decltype(cmpr)> sr(cmpr);
auto add=[&](ll x) {sp.insert(x);sq.insert(x);sr.insert(x);};
for(int i=1;i<=a;i++) add(i);
for(int i=1;i<b;i++) add(1ll*i*a*c+1);
for(int i=1;i<c;i++) add(1ll*i*a+1);
for(int i=2,s=a+b+c-2;s<n;i++)
if(!sp.count(i)) add(i),s++;
map<ll,int> id;
int t=0;
for(ll x:sp) p.push_back(id[x]=++t);
for(ll x:sq) q.push_back(id[x]);
for(ll x:sr) r.push_back(id[x]);
return 1;
}
int main(){
int tot;scanf("%d",&tot);
for(int n,a,b,c,op;tot--;){
p.clear();q.clear();r.clear();
scanf("%d%d%d%d%d",&n,&a,&b,&c,&op);
if(solve(n,a,b,c)){
puts("YES");
if(!op) continue;
for(int x:p) printf("%d ",x);
puts("");
for(int x:q) printf("%d ",x);
puts("");
for(int x:r) printf("%d ",x);
puts("");
}else puts("NO");
}
return 0;
}

浙公网安备 33010602011771号