CCPC-WannaFly-Camp 1057: Kimi to Kanojo to Kanojo no Koi(構造)
时间限制: 1 Sec 内存限制: 1024 MB Special Judge
如果你希望解锁美雪的手机,你需要回答30个问题,只有你非常关注美雪才能全部解答正确。而且,根
据"你"的不同,美雪的行为也是不一样的。对于不同的"你",答案相同的概率为3130。可以说,对于每个
不同的"你",都有一个唯一的美雪。
不过因为美雪现在心情很好,所以你只需要回答一个问题。给一个正整数n,请你输出一个n × n 的
方阵A,满足方阵的每一行,每一列都是一个1 ∼ n 的排列,并且对于所有的1 ≤ i < j ≤ n, 有
Ai,j ̸= Aj,i。
有解输出任意一个方案,否则输出“-1”(不含引号)。
Input
输入仅一行一个整数n(1 ≤ n ≤ 1000)。
Output
如果有解,输出n 行,每行n 个[1, n] 范围内的整数,第i行第j个数表示Ai,j;否则输出“-1”。
Example
standard input
3
standard output
1 3 2
2 1 3
3 2 1
题解:
有三种情况:
1、n 是奇数,我们可以构造如下的方阵:
1, 2, 3, ... n-2, n-1, n
n, 1, 2, ... n-3, n-2, n-1
...
3, 4, 5, ... n, 1, 2
2, 3, 4, ... n-1, n, 1
可知对于所有的i,j (1<=i<j<=n), A[i][j]+A[j][i]=n+2, 所以A[i][j] 不可能等于A[j][i]。
2、n=2,无解。
3、n 为大于2 的偶数:当n = 4 的时候,有这样一组解:
1, 2, 3, 4
4, 3, 2, 1
2, 1, 4, 3
3, 4, 1, 2
当n>4 的时候,我们假设n=2k (k>2), 并且当n=k 时存在一组合法解,那么我们构造n=2k 时的解:
记A(t) 为n=t 时的一组解。首先,我们先令A(2t) 为:
A(k), A(k)
A(k), A(k)
之后, 我们在左上和右下的A(k) 中给所有元素加上k:
A(k)+k, A(k)
A(k), A(k)+k
之后,我们把右上的A(k) 沿着它的主对角线翻转一下并记为A’(k),此时我们可以得到:对于所有在
A’(k) 中的A(2k)[i][j],有A(2k)[i][j] = A(2k)[j][i],具体如下。
A(k)+k, A’(k)
A(k), A(k)+k
最后, 我们只要把左下的A(k) 的值都移一位就好。(1->2, 2->3, ..., k->1):
A(k)+k, A’(k)
A(k)+1, A(k)+k
这样n=2k 的解就构造出来了。
#include <cstdio>
#include <vector>
using namespace std;
const int MAXN = 1005;
int board[MAXN][MAXN];
inline void BuildFour(){
board[1][1] = 1;
board[1][2] = 2;
board[1][3] = 3;
board[1][4] = 4;
for(int i=1 ; i<=4 ; ++i)board[2][i] = 4+1-board[1][i];
board[3][1] = 2;
board[3][2] = 1;
board[3][3] = 4;
board[3][4] = 3;
for(int i=1 ; i<=4 ; ++i)board[4][i] = 4+1-board[3][i];
}
inline void BuildOdd(int i){
int sum = (i*(i+1))/2;
for(int j=1 ; j<=i ; ++j){
int t = j;
for(int k=1 ; k<=i ; ++k){
board[k][t] = j;
++t;
}
}
for(int j=2 ; j<=i ; ++j){
int tt = 0;
for(int k=2 ; k<=i ; ++k)tt += board[j][k];
int t = 1;
for(int k=j ; k<=i ; ++k){
board[k][t] = sum - tt;
++t;
}
}
}
inline void BuildEven(int x){
int t = x;
while(t%2 == 0 && t != 4)t /= 2;
if(t == 4){
BuildFour();
}
else {
BuildOdd(t);
}
for(int i=t ; i<x ; i*=2){
for(int j=i+1 ; j<=i*2 ; ++j){
for(int k=i+1 ; k<=i*2 ; ++k){
board[j][k] = board[j-i][k-i]+i;
}
}
for(int j=1 ; j<=i ; ++j){
for(int k=i+1 ; k<=i*2 ; ++k){
board[j][k] = board[k-i][j];
}
}
for(int j=i+1 ; j<=i*2 ; ++j){
for(int k=1 ; k<=i ; ++k){
board[j][k] = board[j-i][k]+1;
if(board[j][k] == i+1)board[j][k] = 1;
}
}
for(int j=1 ; j<=i ; ++j){
for(int k=1 ; k<=i ; ++k)
board[j][k] += i;
}
}
}
inline void Print(int x){
for(int i=1 ; i<=x ; ++i){
for(int j=1 ; j<x ; ++j)printf("%d ",board[i][j]);
printf("%d\n",board[i][x]);
}
}
int main(){
int N;
while(scanf("%d",&N) == 1){
if(N == 1)printf("1\n");
else if(N == 2)printf("-1\n");
else if(N&1){
BuildOdd(N);
Print(N);
}
else {
BuildEven(N);
Print(N);
}
}
return 0;
}
//
//1 2 3 4
//4 3 2 1
//2 1 4 3
//3 4 1 2
//
/**************************************************************
Problem: 1057
User: 2016203524
Language: C++
Result: 正确
Time:252 ms
Memory:4904 kb
****************************************************************/