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
****************************************************************/

 

posted @ 2018-08-04 16:57  Assassin_poi君  阅读(358)  评论(0编辑  收藏  举报