题意:
给定一个边长为n的正方形,有k种不同颜色的火柴,询问一种合理的摆放位置,使得其满足以下限制:
(1) 所有颜色的火柴数目应该相同
(2) 图中不存在一个单色循环
(3) 某一行或一列至少存在两种颜色。
题解:
其实这题十分简单,赛中忘记特判n=1导致wa了。
先排除没有答案的情况,n=1,k=1,2 * n * (n + 1) % k != 0。
解开这题的关键,是想办法构造每一个小正方形对边颜色不等,容易证明符合上面三种限制。
考虑四种情况:
(1) n < k
颜色的种类大于每一行所需的火柴数量,第一行放置1-n,第二行从n+1开始放,按照这种顺序一直放到k后重新回到1开始,那么第一行的第一根火柴必定跟第二行的第一根火柴颜色不同,同理,容易得到一个符合题意的构造。
(2) n = k
思路是第一行放置1,2,…,n,第二行放置2,3,…,n,第三行放置1,2,…,n,依次类推,列的构造和行的构造一样。
(3) n < k && n % k == 0
举个例子,n = 12 和 k = 4
1 2 3 4 1 2 3 4 1 2 3 4
2 3 4 1 2 3 4 1 2 3 4 1
1 2 3 4 1 2 3 4 1 2 3 4
2 3 4 1 2 3 4 1 2 3 4 1
按照这种构造方式重复构造,思路和第二种相似。
(4) n < k && n % k != 0
举个例子,n = 9 和 k = 5
1 2 3 4 5 1 2 3 4
5 1 2 3 4 5 1 2 3
4 5 1 2 3 4 5 1 2
3 4 5 1 2 3 4 5 1
2 3 4 5 1 2 3 4 5
按照这种构造方式重复构造,思路和第一种相似。
AC_CODE:
int n,k;
R(n,k);
if (2 * n * (n + 1) % k != 0 || k == 1 || n == 1) {
printf("-1\n");
return;
}
if(k > n) {
int ans = 1;
FOR(i,1,2*(n+1)) {
FOR(j,1,n-1) {
printf("%d ",ans++);
if(ans > k) ans -= k;
}
printf("%d\n",ans++);
if(ans > k) ans -= k;
}
} else if(k == n) {
int ans = 1;
bool ok = 0;
FOR(i,1,2*(n+1)) {
if(!ok) {
FOR(j,1,n) {
printf("%d%c",ans++,(j==n?'\n':' '));
}
} else {
FOR(j,1,n-1) {
printf("%d ",++ans);
}
printf("1\n");
}
ok ^= 1;
ans = 1;
}
} else if(n % k == 0) {
int t = n / k;
int ans = 1;
bool ok = 0;
FOR(i,1,2*(n+1)) {
if(!ok) {
FOR(j,1,n-1) {
if(ans > k) ans -= k;
printf("%d ",ans++);
}
if(ans > k) ans -= k;
printf("%d\n",ans++);
} else {
FOR(j,1,n-1) {
if(ans == k) ans -= k;
printf("%d ",++ans);
}
if(ans == k) ans -= k;
printf("%d\n",++ans);
}
ok ^= 1;
ans = 1;
}
} else {
int ans = 1;
FOR(i,1,2*(n+1)) {
FOR(j,1,n-1) {
if(ans > k) ans -= k;
printf("%d ",ans++);
}
if(ans > k) ans -= k;
printf("%d\n",ans++);
}
}