填表格

Description

有一个N行N列的格子,现在要把1~N^2的所有整数填进这些格子中。有这样一些规则: 
(1)1可以填在任意一个位置; 
(2)i所在的行序号等于i-1所在的列序号,2<=i<=N^2; 
(3)按从小到大的顺序填,每个格子只能填一个数。 
有时可以把这些数填完,有时候则不行。例如,下图所示即为N=3时的一个可行方案。由于1在第3列,所以2要填在第3行,以此类推,直到把9填进去使其填满。 
 

现在,如果我们要求1所在的行的所有数字之和与N2所在列的所有数字之和尽量接近,请问最小可能相差多少。

例如上图,1所在的行的所有数字之和为15,9所在列的所有数字之和为21,相差6,正好也是最优方案。

Input

第一行为一个整数T,表示有T组测试数据;接下来有T行,每行表示一组测试数据,即一个整数N。

Output

对每组测试数据输出一行,仅含一个整数,表示1所在行的数字和与N^2所在列的数字和的差的绝对值的最小值。

如果不存在可行解,即无法填满,输出-1。

Sample Input

2
2
3

Sample Output

2
6

Hint

对于20%的数据,保证1<=T<=10,1<=N<=10 
对于70%的数据,保证1<=T<=20,1<=N<=1000 
对于所有的数据,保证1<=T<=100,1<=N<=40000


【分析】

        这道题非常有意思。也许有人会想到DFS,但是一看数据范围,就知道是不可能的。这种算法不是多项式级别的,超时是稳稳的。但是在没有思路的时候,可以写个DFS然后求出几组数据来观察一下。(注:搜索的时候要加个计数器优化,不然6以上就要等很久)。搜索后知道:N=4时,ans=12;N=5时,ans=20;N=6时,ans=30......;

        不难发现规律是ans=N^2-N

        但是为什么呢?我们可以通过简单的数学分析得到答案。

数字行数列数
1X1Y1
2X2Y2
3X3Y3
.........
N^2-1X(N^2-1)Y(N^2-1)
N^2X(N^2)Y(N^2)
        由题意知道,Xi=Y(i-1)  所以上述表格中的X2=Y1;X3=Y2;X4=Y3;X(N^2)=Y(N^2-1);

        最后只剩下X1和Y(N^2)没有对应了,又由分析知,行数那一列的和,与列数那一列的和是相等的。又Xi=Y(i-1),所以自然X1=Y(N^2)成立。

        也就是说1所在的行的编号,等于N^2所在的列的编号

        再来考虑向N^2所在的列加入某个数字a,由题意知,a+1一定在1所在的行。而一行或一列只有N个数字可以填,而1和N^2又各占了一个位置。所以像a这样的数字,可以填N-1个。

        那么我们用N^2来减去1,用a来减去a+1。所以最后,ans=N^2-1+(a-(a+1))*(N-1)=N^2-1+(-1)*(N-1)=N^2-N;

        综上所述,ans=N^2-N;

(ps:题目中所说的无解的情况是没有的,只要有一个N,那么就有一个ans);


【代码】(这个就太简单了)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
int T,N;
void _init()
{
     scanf("%d",&T);
}
void _solve()
{
     for(int i=1;i<=T;i++)
     {
         scanf("%d",&N);
         printf("%d\n",N*(N-1));
     }
}
int main()
{
    _init();
    _solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值