链接:https://ac.nowcoder.com/acm/contest/5671/G
来源:牛客网
Roundgod draws a grid graph of size nn with n × n n \times n n×n cells. She can use one of k k k colors to color every edge once, but lzr gives her some limits.
Roundgod is so divine that she doesn’t want to waste her god’s power to solve this problem. Could you give her a solution?
输入描述:
The input contains multiple test cases. The first line of input contains one integer T ( 1 ≤ T ≤ 100 ) T\ (1\le T\le100) T (1≤T≤100).
In the following T T T lines, each line contains two integers n , k ( 1 ≤ n ≤ 200 , 1 ≤ k ≤ 2 ( n + 1 ) n ) n,k\ (1\le n\le200,1\le k\le2(n+1)n) n,k (1≤n≤200,1≤k≤2(n+1)n) describing one test case.
输出描述:
For each test case, if there’s no solution, please output “-1”.
Otherwise, output 2 ( n + 1 ) 2(n+1) 2(n+1) lines.
For the first n + 1 n+1 n+1 lines, each line contains nn integers, denoting colors of edges on every horizontal line.
For the last n + 1 n+1 n+1 lines, each line contain nn integers, denoting colors of edges on every vertical line.
示例1
输入
2
2 3
2 5
输出
1 2
3 1
3 2
1 3
2 1
2 3
-1
首先,对于 n = 1 n=1 n=1或 k = 1 k=1 k=1或 ( 2 ⋅ ( n + 1 ) ⋅ n ) m o d k ≠ 0 (2 · (n + 1) · n)\mod k\not=0 (2⋅(n+1)⋅n)modk=0的情况直接输出 − 1 -1 −1。
对于其他情况,首先把要填的数字相同的写在一起组成序列 s e q seq seq。如 n = 3 n=3 n=3, k = 4 k=4 k=4的情况 s e q = 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 4 , 4 , 4 , 4 , 4 , 4 seq=1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 ,2 ,3 ,3 ,3 ,3 ,3 ,3 ,4 ,4 ,4 ,4 ,4 ,4 seq=1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4。
然后按下图所示顺序依次填入各边。
如果按照这种策略填写,首先一定满足不存在环使得环的边颜色相同。
证明:首先 k ≥ 2 k≥2 k≥2,而按照这种策略红色的边和黑色的边数量相等,因此红色的边与黑色的边的颜色一定不同,而对于图中任意一个环一定同时包含红色的边和黑色的边,因此一定不存在环使得环的边颜色相同。
其次是对于任意一个行和列的边颜色不能相同。由于行和列对称,因此这里就各列进行讨论。
经验证发现只有样例的第一个数据不满足,其余情况都满足。
这里就大概证明一下,可能不是很严谨。
若某一列颜色都相同,设该列的边中编号最小的为 i m i n i_{min} imin,最大的为 i m a x i_{max} imax,则应当满足 m i n ( i m i n , 2 ⋅ ( n + 1 ) ⋅ n − i m a x ) ≥ 2 ⋅ ( n + 1 ) ⋅ n 3 min(i_{min},2·(n+1)·n-i_{max})≥\frac{2·(n+1)·n}{3} min(imin,2⋅(n+1)⋅n−imax)≥32⋅(n+1)⋅n。
对于 n = 2 n=2 n=2, k = 3 k=3 k=3,中间一列刚好满足等号条件。
而随着 n n n的增长,取得 i m i n i_{min} imin的边会逐渐由上一条红边跳到下一条包含边数更多的边上,而由于图中红线包含的边数增长部分为线性增长,因此这一变化可以近似看做是线性增长;同理, 2 ⋅ ( n + 1 ) ⋅ n − i m a x 2·(n+1)·n-i_{max} 2⋅(n+1)⋅n−imax也可以看做是线性增长的,而等式右边 2 ⋅ ( n + 1 ) ⋅ n 3 ∝ n 2 \frac{2·(n+1)·n}{3}∝n^2 32⋅(n+1)⋅n∝n2,因此除样例外都满足条件。
#include
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector
#define pii pair
#define mii unordered_map
#define msi unordered_map
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<
using namespace std;
inline int qr() {
int f = 0, fu = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')fu = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
f = (f << 3) + (f << 1) + c - 48;
c = getchar();
}
return f * fu;
}
const int N = 405, M = 1e5 + 10;
int T, n, m, k;
int seq[M];
int a[N][N];
inline void change(int x, int y, int z, int v) {
switch (z) {
case 1:
a[2 * x - 1][y] = v;
break;
case 2:
a[2 * x + 1][y] = v;
break;
case 3:
a[2 * x][y] = v;
break;
default:
a[2 * x][y + 1] = v;
}
}
inline int ask(int x, int y, int z) {
switch (z) {
case 1:
return a[2 * x - 1][y];
case 2:
return a[2 * x + 1][y];
case 3:
return a[2 * x][y];
default:
return a[2 * x][y + 1];
}
}
inline void solve() {
int tot = 0, i = 2;
for (; i - 1 <= n; i += 2)
repi(j, 1, i - 1) {
change(j, i - j, 1, seq[++tot]);
change(j, i - j, 3, seq[++tot]);
}
i--;
for (; i <= 2 * n; i += 2)
repi(j, i - n, n) {
change(j, i - j, 4, seq[++tot]);
change(j, i - j, 2, seq[++tot]);
}
i = 3;
for (; i - 1 <= n; i += 2)
repi(j, 1, i - 1) {
change(j, i - j, 1, seq[++tot]);
change(j, i - j, 3, seq[++tot]);
}
i--;
for (; i <= 2 * n; i += 2)
repi(j, i - n, n) {
change(j, i - j, 4, seq[++tot]);
change(j, i - j, 2, seq[++tot]);
}
}
int main() {
T = qr();
while (T--) {
n = qr(), k = qr();
if (n == 2 && k == 3) {
puts("1 2\n3 1\n3 2\n1 3\n2 1\n2 3");
continue;
}
if ((2 * (n + 1) * n) % k || n == 1 || k == 1) {
puts("-1");
continue;
}
m = (2 * (n + 1) * n) / k;
repi(i, 1, k)repi(j, 1, m)seq[(i - 1) * m + j] = i;
solve();
repi(i, 1, n)repi(j, 1, n)printf("%d%c", ask(i, j, 1), ce(j, n));
repi(i, 1, n)printf("%d%c", ask(n, i, 2), ce(i, n));
repi(i, 1, n)repi(j, 1, n)printf("%d%c", ask(j, i, 3), ce(j, n));
repi(i, 1, n)printf("%d%c", ask(i, n, 4), ce(i, n));
}
return 0;
}