@Modulo Matrix@
@题目描述 - English@
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : 1100 points
Problem Statement
You are given an integer N.Construct any one N-by-N matrix a that satisfies the conditions below. It can be proved that a solution always exists under the constraints of this problem.
1≤a(i,j)≤10^15
a(i,j) are pairwise distinct integers.
There exists a positive integer m such that the following holds: Let x and y be two elements of the matrix that are vertically or horizontally adjacent. Then, max(x,y) mod min(x,y) is always m.
Constraints
2≤N≤500
Input
Input is given from Standard Input in the following format:
N
Output
Print your solution in the following format:
a(1,1)…a(1,N)
…
a(N,1) … a(N,N)
Sample Input 1
2
Sample Output 1
4 7
23 10
For any two elements x and y that are vertically or horizontally adjacent, max(x,y) mod min(x,y) is always 3.
@中文题意@
构造一个元素互不相同的N*N矩阵,矩阵元素为不超过10^15的正整数。使得对于矩阵中相邻的两个元素x,y, 为一个正整数常数。
@分析@
假如没有元素互不相同的限制,我们可以对矩阵黑白二染色,形成棋盘状。然后在黑格里填N,白格里面填N+1。
那么现在有了元素互不相同的限制,我们仍然可以沿用这样一个染色思想:令(1,1)为黑格,交替染色,使得白格里的元素总大于它四周黑格的元素。并且为了简化问题,不妨让模数值为 1,这样问题转化为(白格元素值-1)是它四周黑格元素的公倍数。一样为了简化问题,我们令白格元素=四周黑格元素的LCM + 1。
构造思路出来了,但是还有一个很严重的问题:直接这样构造是会超出题目所给的10^15的范围。
【于是考场上我就想到这里而已……QAQ】
我们给每一条黑格斜线定一个素数权值,给每一个黑格定权值为穿过它两条斜线——自左上至右下一条,自右上至左下一条——的权值之积。这样,每个白格的元素就为四个素数之积+1。
不难发现自右上至左下的斜线恰有N条,我们令这N条斜线的权值为第1~N个质数,令自左上至右下的斜线的权值为N+1开始的质数。
则白格的最大值为
这样就很完美了。
@代码@
QAQ实际上我自己都没有完全过掉这道题……
不过如果米娜桑如果还有什么问题的话,我也会尽力解疑的~
【UPD in 2018/9/22】发现像之前那么写的话会有两个数相同……还真的要特判QWQ
#include<cstdio>
typedef long long ll;
const int MAXN = 500;
const int MAXM = 10000;
bool vis[MAXM + 5];
int prm[MAXM + 5], pcnt = 0;
ll GCD(ll x, ll y) {
return y == 0 ? x : GCD(y, x%y);
}
ll LCM(ll x, ll y) {
return x / GCD(x, y) * y;
}
void sieve() {
for(int i=2;i<=MAXM;i++) {
if( !vis[i] ) prm[++pcnt] = i;
for(int j=1;i*prm[j]<=MAXM;j++) {
vis[i*prm[j]] = true;
if( i % prm[j] == 0 ) break;
}
}
}
ll Mat[MAXN + 5][MAXN + 5];
int main() {
sieve(); int N;
scanf("%d", &N);
if( N == 2 ) {
printf("4 7\n23 10\n");
return 0;
}
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
Mat[i][j] = 1;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if( (i & 1) == (j & 1) ) {
Mat[i][j] = prm[(i + j) / 2] * prm[(i+N+1-j)/2 + N];
Mat[i+1][j] = LCM(Mat[i+1][j], Mat[i][j]);
Mat[i-1][j] = LCM(Mat[i-1][j], Mat[i][j]);
Mat[i][j+1] = LCM(Mat[i][j+1], Mat[i][j]);
Mat[i][j-1] = LCM(Mat[i][j-1], Mat[i][j]);
}
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if( (i & 1) != (j & 1) )
Mat[i][j]++;
for(int i=1;i<=N;i++) {
for(int j=1;j<N;j++)
printf("%lld ", Mat[i][j]);
printf("%lld\n", Mat[i][N]);
}
}
@END@
就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~