题目背景
滴——🎵 滴——🎵 踹1叉!🎵 你真了不得🎵 黑题构造,难不住你🎵 杀出个王校长!🎵
题目描述
可见于校长的博客。
啥也不会,先考虑拿 m = 2 n + 1 m=2n+1 m=2n+1 部分分。手玩较小的情况,发现 n = 2 n=2 n=2 有解,并可由此得到所有 2 ∣ n 2\mid n 2∣n 。但 n = 1 n=1 n=1 和 n = 3 n=3 n=3 都无解。猜测 2 ∤ n 2\nmid n 2∤n 无解。赛时我就想不明白这是为什么,所以我就寄了 😓
事实上我们注意到:记 p i ( 1 ⩽ i ⩽ 2 n ) p_i\;(1\leqslant i\leqslant 2n) pi(1⩽i⩽2n) 为,走完 [ i − 1 , i ] [i{-}1,i] [i−1,i] 这一段之后,接下来应当走哪一段。最初 p i = i + 1 p_i=i+1 pi=i+1,特别地,令 p 2 n = 1 p_{2n}=1 p2n=1 。那么 a , b a,b a,b 之间建立虫洞,等价于交换 p a , p b p_a,p_b pa,pb 。最后 p i p_i pi 构成一个 置换,与 1 1 1 在同一置换环中的点会被走过。
那么 m = 2 n + 1 m=2n+1 m=2n+1 希求一个完整的偶长度置换环,然而 2 ∤ n 2\nmid n 2∤n 表明它是奇排列,于是寄了。
想到置换是比较关键的。话又说回来,当你意识到 “不可能死循环” 的时候,你就应该从置换的角度去思考了啊 😢
然后考虑 m ⩽ 8 m\leqslant 8 m⩽8 这样的部分分。发现两侧都不被经过的点,可以任意配对,并且这样的点也只能内部匹配。
由此,我们按照左右两侧的需要被经过情况,分出四类点 N ( o n e ) , A ( l l ) , L ( e f t ) , R ( i g h t ) N(one),A(ll),L(eft),R(ight) N(one),A(ll),L(eft),R(ight) 。那么显然的, N N N 和 N N N 配对, L L L 和 R R R 配对, A A A 和 A A A 配对。那么 N N N 类点就不必再考虑了。这是 简化问题 的方式。
于是剩下 A L R A L R A ALRALRA ALRALRA 之类的东西。如果 A A A 的数量是 4 4 4 的倍数,直接用 m = 2 n + 1 m=2n+1 m=2n+1 方案构造即可,因为此时 L R LR LR 相当于路上的小插曲。如果 A A A 的数量不是 4 4 4 的倍数,我们知道,关键矛盾在于逆序对奇偶性。那么大概需要一对 L R A A L R {\color{red}L}{\color{blue}R}AA{\color{blue}L}{\color{red}R} LRAALR,然后蓝配蓝、红配红。
画图可见,它的效果是内部一个置换环、外部一个置换环。手玩可知,只要两个环都存在 A A A,二者就可以被拼接起来。与之相对的,如果没有这样的 pattern \text{pattern} pattern 就无解。因为这是唯一拯救这罪恶的逆序对的方法。
当然上面只表明了有解,实际上构造解的方式很 s i m p l e \rm simple simple:只需找到 A L R A L R ALRALR ALRALR,除了 L R LR LR 按照之前所说的 pattern \text{pattern} pattern 连,再把 A A AA AA 连上就行。当然外面的 A A A 也可以在右。
#include <cstdio>
#include <algorithm> // Almighty XJX yyds!!
#include <cstring> // oracle: ZXY yydBUS!!!
#include <cctype> // Huge Egg Dog ate me!!!
#include <cstdlib>
using llong = long long;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
# define rep0(i,a,b) for(int i=(a); i!=(b); ++i)
inline int readint(){
int a = 0, c = getchar(), f = 1;
for(; !isdigit(c); c=getchar()) if(c == '-') f = -f;
for(; isdigit(c); c=getchar()) a = a*10+(c^48);
return a*f;
}
const int MAXN = 200005;
bool vis[MAXN]; int match[MAXN];
int nxt[MAXN];
int main(){
int n = readint(), m = readint(), cnta = 0;
while(m--) vis[readint()] = true;
{ // basic matching for 'N'
int lstn = -1;
for(int i=1; i<=(n<<1); ++i)
if(!vis[i-1] && !vis[i]){ // 'N'
if(!(~lstn)){ lstn = i; continue; }
match[i] = lstn, match[lstn] = i, lstn = -1;
}
else if(vis[i-1] && vis[i]) ++ cnta;
if(~lstn){ puts("No"); return 0; }
}
if((cnta&3) == 2){
bool flag = false;
rep(i,1,n<<1) if(vis[i-1] && vis[i]){ // 'A'
int rig = i; while(rig <= (n<<1) &&
vis[rig-1] && vis[rig]) ++ rig;
int zuo[3] = {0,0,0};
for(int j=i-1; j; --j)
if(!vis[j-1] && vis[j]) zuo[2] = j;
else if(vis[j-1] && !vis[j]){
zuo[1] = j; break; // collected
}
if(!zuo[1]){ i = rig-1; continue; }
for(int j=zuo[1]-1; j; --j)
if(vis[j-1] && vis[j]){
zuo[0] = j; break;
}
int you[3] = {i,i,i};
for(int j=i+1; j<=(n<<1); ++j)
if(vis[j-1] && !vis[j]) you[0] = j;
else if(!vis[j-1] && vis[j]){
you[1] = j; break;
}
if(you[1] != i)
for(int j=you[1]+1; j<=(n<<1); ++j)
if(vis[j-1] && vis[j]){
you[2] = j; break;
}
if(zuo[0] && you[1] != i){ // link to left
match[zuo[0]] = i, match[i] = zuo[0];
match[zuo[1]] = you[1], match[you[1]] = zuo[1];
match[zuo[2]] = you[0], match[you[0]] = zuo[2];
flag = true; break;
}
if(zuo[1] && you[2] != i){ // link to right
match[rig-1] = you[2], match[you[2]] = rig-1;
match[zuo[1]] = you[1], match[you[1]] = zuo[1];
match[zuo[2]] = you[0], match[you[0]] = zuo[2];
flag = true; break;
}
i = rig-1; // skip the segment
}
if(!flag){ puts("No"); return 0; }
}
int lstl = -1, lsta[4] = {-1,-1,-1,-1};
puts("Yes"); // can be sure
for(int i=1|(cnta=0); i<=(n<<1); ++i){
if(match[i]){
if(match[i] < i)
printf("%d %d\n",match[i],i);
continue; // 'N' or known
}
if(vis[i-1] && vis[i]){ // 'A'
lsta[cnta++] = i;
if(cnta == 4){ // done
printf("%d %d\n%d %d\n",lsta[0],
lsta[2],lsta[1],lsta[3]);
cnta = 0; // reset
}
}
else if(vis[i-1]) // 'L'
lstl = i; // assert(lstl == -1);
else printf("%d %d\n",lstl,i);
}
return 0;
}
作词者 Rainybunny \textsf{Rainybunny} Rainybunny,意即 XY \text{XY} XY,叉歪。 ↩︎