[COCI2016-2017#2] Prosječni 解题记录
题意简述
构造一个 n × n n \times n n×n 的矩阵,使得每一行/列的平均都在这一行/列当中,并且矩阵内各个数字不相同。
题目分析
观察样例就可以轻松发现:当 n n n 为奇数时,矩阵内的各个元素就是 1 ∼ n 1 \sim n 1∼n 的按顺序排列。
证明:
- 对于每一行,公差为 1 1 1,设每一行第一个数为 x x x,第 k k k 项为 x + ( k − 1 ) x+(k-1) x+(k−1) 其中 1 ≤ k ≤ n 1 \leq k \leq n 1≤k≤n,那么这一行的和就是 ( x + x + n − 1 ) × n 2 \frac{(x+x+n-1)\times n}{2} 2(x+x+n−1)×n,平均数是 x + x + n − 1 2 = x + ( n − 1 ) 2 \frac{x+x+n-1}{2}=x+\frac{(n-1)}{2} 2x+x+n−1=x+2(n−1)。
- 因为 n n n 是奇数,所以 n − 1 2 \frac{n-1}{2} 2n−1 是整数,且 1 ≤ n − 1 2 ≤ n 1 \leq \frac{n-1}{2} \leq n 1≤2n−1≤n。
- 每一列同理。
证毕。
如果 n n n 为偶数,我们以同样的方式构造,每一行的平均数同样为 x + ( n − 1 ) 2 \frac{x+(n-1)}{2} 2x+(n−1),但是这个时候它是小数,我们只需要对这个矩阵的每一项都 × 2 \times 2 ×2,这样平均数就变成了 x + ( n − 1 ) x+(n-1) x+(n−1) 这个整数。但是它也是一个奇数,怎么办呢?因为我们构造的矩阵公差相同,所以和平均数最相近的两个数肯定是中间的,为了使和不变,我们可以将每一行的第 n ÷ 2 n\div2 n÷2 项 + 1 +1 +1,同时将第 n ÷ 2 + 1 n \div 2+1 n÷2+1 项 − 1 -1 −1,那么每一行就构造完成了(这里也说明了只有 n = 2 n=2 n=2 的时候才无解)。
接下来考虑每一列,只需要将最后一行加上 n 2 n^2 n2 即可满足条件。
证明: - 对于每一列,公差为 2 n 2n 2n,设每一列第一个数为 x x x,第 k k k 项就为 x + ( k − 1 ) × 2 n x+(k-1)\times 2n x+(k−1)×2n 其中 1 ≤ k ≤ n 1 \leq k \leq n 1≤k≤n,那么这一列的和就是 [ x + x + ( n − 1 ) × 2 n ] × n 2 \frac{[x+x+(n-1) \times 2n]\times n}{2} 2[x+x+(n−1)×2n]×n,平均数是 x + x + ( n − 1 ) × 2 n 2 = x + n ( n − 1 ) = x + n − 1 2 × 2 n \frac{x+x+(n-1) \times 2n}{2}=x+n(n-1)=x+\frac{n-1}{2} \times 2n 2x+x+(n−1)×2n=x+n(n−1)=x+2n−1×2n。
- 因为 n n n 是偶数,所以 n − 1 2 \frac{n-1}{2} 2n−1 不是整数,但是 n 2 \frac{n}{2} 2n 是,所以考虑将每列的最后一项加上 n 2 n^2 n2,等价于将每一项加上 n n n,平均数也加上 n n n,变为 x + n 2 × 2 n x+\frac{n}{2} \times 2n x+2n×2n,其中 1 ≤ n 2 ≤ n 1\leq \frac{n}{2} \leq n 1≤2n≤n。
证毕。
AC Code
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
CI N=105;
int n,a[N][N];
signed main() {std::cin>>n;if(n==2) {puts("-1");exit(0);}int k=0;rep(i,1,n) {rep(j,1,n) {a[i][j]=++k;}}if(n&1) {rep(i,1,n) {rep(j,1,n) {std::cout<<a[i][j]<<" ";}puts("");}} else {rep(i,1,n) {rep(j,1,n) {a[i][j]*=2;}}rep(i,1,n) {a[i][n/2]++;a[i][n/2-1]--;}rep(i,1,n) {a[n][i]+=n*n;}rep(i,1,n) {rep(j,1,n) {std::cout<<a[i][j]<<" ";}puts("");}}return 0;
}