题解:P9841 [ICPC 2021 Nanjing R] Puzzle in Inazuma
以下是一大坨。
Part 1
首先可以令
一个显然的想法是把
具体地,设当前枚举的点为
最后剩下
给出第一个操作组:选定四个点
操作:记初始
可以画图发现这是对的。
所以如果
如果只看奇偶性的话,进行一次
也就是:有
无论如何都可以做到。下面不带编号地给出做法:
所以一定可以把
Part 2
现在问题变成了一个
首先边权和必定要为
其次,
所以可以得出结论:
这是另一个必要条件。
然后,进行加减消元,可以得出:
所以右边三项都得是偶数,这是第三个必要条件。
都满足后,令
Part 3
你要是认为这就做完了就大错特错了(这么认为的我就是大奶龙)。
以上只是
我们已经知道了第一个操作组——对偶数边权的转移。所以给出结论:当且仅当剩下的
必要性证明略。充分性证明:如果权值都是奇数就先做一次
Part 4
然而还没有完。
给出第二个操作组:令
操作:先操作
画个图更容易理解。
所以,先判定边权和为
总结
把
分析以下,除了一开始把其他边变成
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
int G[maxn][maxn], H[maxn][maxn];
int ans[maxn * maxn * maxn][5], cnt = 0;
void operateG(int a, int b, int c, int d, int w){
cnt ++, ans[cnt][0] = a, ans[cnt][1] = b, ans[cnt][2] = c, ans[cnt][3] = d, ans[cnt][4] = w;
G[a][b] += w, G[b][a] += w, G[a][c] += w, G[c][a] += w, G[a][d] += w, G[d][a] += w;
G[b][c] -= w, G[c][b] -= w, G[c][d] -= w, G[d][c] -= w, G[b][d] -= w, G[d][b] -= w;
}
void solve_even(){
operateG(3, 1, 2, 4, G[1][2] / 2), operateG(4, 1, 2, 3, G[1][2]);
operateG(4, 1, 2, 3, G[1][3] / 2), operateG(2, 1, 3, 4, G[1][3]);
operateG(2, 1, 3, 4, G[1][4] / 2), operateG(3, 1, 2, 4, G[1][4]);
operateG(1, 2, 3, 5, G[2][3] / 2), operateG(5, 1, 2, 3, G[2][3]);
operateG(1, 3, 4, 5, G[3][4] / 2), operateG(5, 1, 3, 4, G[3][4]);
operateG(2, 1, 4, 5, G[1][5] / 2), operateG(4, 1, 2, 5, G[1][5]);
}
void swap_one(int a, int b, int c, int d){
operateG(5, a, b, c, 1), operateG(d, b, c, 5, 1);
operateG(6, a, b, c, -1), operateG(d, b, c, 6, -1);
operateG(6, 5, a, d, 1);
}
int main(){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++){
for(int j = i + 1; j <= n; j ++){
scanf("%d", &G[i][j]);
G[j][i] = G[i][j];
}
}
for(int i = 1; i <= n; i ++){
for(int j = i + 1; j <= n; j ++){
scanf("%d", &H[i][j]);
H[j][i] = H[i][j];
G[i][j] -= H[i][j], G[j][i] -= H[j][i];
}
}
for(int x = n; x >= 5; x --){
for(int i = n; i >= 5; i --){
if(i == x) continue;
operateG(x, 1, 2, i, -G[x][i]);
}
int a = G[x][1] & 1, b = G[x][2] & 1, c = G[x][3] & 1, d = G[x][4] & 1;
if(a + b + c + d == 4){
operateG(x, 1, 2, 3, 1);
operateG(x, 1, 2, 4, 1);
operateG(x, 1, 3, 4, 1);
operateG(x, 2, 3, 4, 1);
}else if(a + b + c + d == 3){
if(!a) operateG(x, 2, 3, 4, 1);
else if(!b) operateG(x, 1, 3, 4, 1);
else if(!c) operateG(x, 1, 2, 4, 1);
else operateG(x, 1, 2, 3, 1);
}else if(a + b + c + d == 2){
if(a && b) operateG(x, 2, 3, 4, 1), operateG(x, 1, 3, 4, 1);
else if(a && c) operateG(x, 2, 3, 4, 1), operateG(x, 1, 2, 4, 1);
else if(a && d) operateG(x, 2, 3, 4, 1), operateG(x, 1, 2, 3, 1);
else if(b && c) operateG(x, 1, 2, 4, 1), operateG(x, 1, 3, 4, 1);
else if(b && d) operateG(x, 1, 2, 3, 1), operateG(x, 1, 3, 4, 1);
else operateG(x, 1, 2, 3, 1), operateG(x, 1, 2, 4, 1);
}else if(a + b + c + d == 1){
if(a) operateG(x, 1, 2, 3, 1), operateG(x, 1, 2, 4, 1), operateG(x, 1, 3, 4, 1);
else if(b) operateG(x, 1, 2, 3, 1), operateG(x, 1, 2, 4, 1), operateG(x, 2, 3, 4, 1);
else if(c) operateG(x, 1, 2, 3, 1), operateG(x, 1, 3, 4, 1), operateG(x, 2, 3, 4, 1);
else operateG(x, 1, 2, 4, 1), operateG(x, 1, 3, 4, 1), operateG(x, 2, 3, 4, 1);
}
a = -G[x][1] / 2, b = -G[x][2] / 2, c = -G[x][3] / 2, d = -G[x][4] / 2;
operateG(x, 1, 2, 3, a), operateG(1, x, 2, 3, a);
operateG(x, 2, 1, 3, b), operateG(2, x, 1, 3, b);
operateG(x, 3, 1, 2, c), operateG(3, x, 1, 2, c);
operateG(x, 4, 1, 2, d), operateG(4, x, 1, 2, d);
}
int w12 = -G[1][2], w13 = -G[1][3], w14 = -G[1][4], w23 = -G[2][3], w24 = -G[2][4], w34 = -G[3][4];
if(n == 4){
if(w12 + w34 != 0 || w13 + w24 != 0 || w14 + w23 != 0){
printf("-1\n");
return 0;
}
if(((w12 + w13) & 1) || ((w12 + w23) & 1) || ((w13 + w23) & 1)){
printf("-1\n");
return 0;
}
int x1 = (w12 + w13) / 2, x2 = (w12 + w23) / 2, x3 = (w13 + w23) / 2;
operateG(1, 2, 3, 4, x1), operateG(2, 1, 3, 4, x2), operateG(3, 1, 2, 4, x3);
}else if(n == 5){
int sum = (w12 & 1) + (w13 & 1) + (w14 & 1) + (w23 & 1) + (w24 & 1) + (w34 & 1);
if((sum != 0 && sum != 6) || (w12 + w13 + w14 + w23 + w24 + w34 != 0)){
printf("-1\n");
return 0;
}
if(sum == 6) operateG(1, 2, 3, 4, 1);
solve_even();
}else{
if(w12 + w13 + w14 + w23 + w24 + w34 != 0){
printf("-1\n");
return 0;
}
if(G[1][2] & 1) swap_one(1, 3, 4, 2);
if(G[1][3] & 1) swap_one(1, 2, 4, 3);
if(G[1][4] & 1) swap_one(1, 2, 3, 4);
if(G[2][3] & 1) swap_one(2, 1, 4, 3);
if(G[2][4] & 1) swap_one(2, 1, 3, 4);
if(G[3][4] & 1) swap_one(3, 1, 2, 4);
operateG(1, 2, 5, 6, G[5][6] / 2), operateG(2, 1, 5, 6, G[5][6]);
solve_even();
}
printf("%d\n", cnt);
for(int i = 1; i <= cnt; i ++) printf("%d %d %d %d %d\n", ans[i][0], ans[i][1], ans[i][2], ans[i][3], ans[i][4]);
return 0;
}