题意:构造一个矩阵,使得不存在这样一个子矩阵,子矩阵的四个角都为1
思路:
首先用常用的数论构造方法,假设n=5^2,那么矩阵可以写作这种形式:
xxxxx xxxxx xxxxx xxxxx xxxxx
xxxxx xxxxx xxxxx xxxxx xxxxx
xxxxx xxxxx xxxxx xxxxx xxxxx
xxxxx xxxxx xxxxx xxxxx xxxxx
xxxxx xxxxx xxxxx xxxxx xxxxx
省略后面的20行...
我们先拿第一个5*25的矩阵举例,按照下面的规则进行填充:
每5个为1块,每块填1个1。
每行以10000开始。
第0行每块的1的位置逐次+0,第1行每块的1的位置逐次+1,第2行每块的1的位置逐次+2...(mod 5)
可以得到:
10000 10000 10000 10000 10000
10000 01000 00100 00010 00001
10000 00100 00001 01000 00010
10000 00010 01000 00001 00100
10000 00001 00010 00100 01000
我们继续构造第二个5*25的矩阵,这个矩阵就是把上一个矩阵每一块的1的位置+1(mod 5)
可以得到:
01000 01000 01000 01000 01000
01000 00100 00010 00001 10000
01000 00010 10000 00100 00001
01000 00001 00100 10000 00010
01000 10000 00001 00010 01000
剩余矩阵同理
现在证明一下这样构造的正确性:
首先按照上面的构造方式写出方程,这里直接给出代码:
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
a[i*n + j][k * n + (j * k + i) % n] = 1;
}
}
}
我们设C1,C2为同一行中数值为1的两列,并设他们在这一行的块号为k1, k2
那么对于(i,j)确定的行,第k1块,有j * k1 + i ≡ C1(mod n)
对于(i,j)确定的行,第k2块,有j * k2 + i ≡ C2(mod n)
得到:j*(k1-k2) ≡ (C1-C2) (mod n)
若n为素数,则方程有唯一解
这样我们便可以解得唯一的(i,j),也就是说不会有两行的C1,C2列都为1,即没有四角都为1的矩阵
剩下的就是拿素数往里面带了,发现只有n=47的时候才有超过85000个1,满满的恶意...
n必须是素数!!!!!!
为什么选47?43是小于sqrt(2000)的最大的素数,发现43不行就选择47
#include <cstdio>
using namespace std;
const int maxn = 2500;
int a[maxn][maxn];
int main() {
for (int i = 0; i < 47; i++) {
for (int j = 0; j < 47; j++) {
for (int k = 0; k < 47; k++) {
a[i*47 + j][k * 47 + (j * k + i) % 47] = 1;
}
}
}
printf("%d\n", 2000);
for (int i = 0; i < 2000; i++) {
for (int j = 0; j < 2000; j++) {
printf("%d", a[i][j]);
}
printf("\n");
}
return 0;
}