1486: 小明的数学
时间限制: 1 Sec 内存限制: 128 MB提交: 101 解决: 22
[ 提交][ 状态][ 讨论版]
题目描述
给一个整数n,你能告诉我有多少种方式写成:n = i * j + i + j (0 < i <= j)
输入
第一行T(<2000).接下来T行,每行一个整数n.
输出
一行一个整数。
这题也算一个水题吧,找到了关键才能AC,可惜楼主也是交了五六次才AC了。。。
思路:上来首先吐槽一下出题者,不说n的范围。这题一开始我就找了一下规律,打了个表。规律显然,自己看图。
所以我就先写成矩阵模式,大家看的懂一些
3 5 7 9 11 13 15
5 8 11 14 17 20 23
7 11 15 19 23 27 31
....不想打字了,懒
显然每一行都是一个等差数列,并且首项也是等差的,这就好办了。我第一想法是看n是否在每一行中,复杂度O(n/2),华丽丽的TLE了,
后来我就改变了策略,先看主对角线(主对角线不懂得看看离散数学),他就是i==j构成的,简化就是i(i+2),如果在的话 ,sum++,在以对角线
后一元素为起点(首项),判断是否在这一行,这样递增的速度就大幅增加,不会超时了,然后就是等差数嘛,公式很好推,行数从一开始,每一行
首元素就是i(i+1)-1,公差就是i,我用LL 花了600ms,换了int好像200ms就AC了。。。上代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
int T,n,sum,k;
scanf("%lld",&T);
while(T--)
{
sum=0;
scanf("%d",&n);
k=floor(sqrt(n*1.0));
if(k*(k+2)==n) sum=1;
for(int i=2; n>=(i+1)*i-1; i++) ///for就是找右边的元素,是否在这一行
if((n-((i+1)*i-1))%i==0) sum++;///刚开始我是吧它乘以2,因为i,j是对称的,上方有,下方就有
printf("%d\n",sum); ///然后三次WA (⊙o⊙)…,后来一看题,i<=j。。。
///所以就砍掉了一半数据,不用乘以2咯
}
return 0;
}