C - An easy problem
Time Limit:3000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Description
When Teddy was a child , he was always thinking about some simple math problems ,such as “What it’s 1 cup of water plus 1 pile of dough ..” , “100 yuan buy 100 pig” .etc..
One day Teddy met a old man in his dream , in that dream the man whose name was“RuLai” gave Teddy a problem :
Given an N , can you calculate how many ways to write N as i * j + i + j (0 < i <= j) ?
Teddy found the answer when N was less than 10…but if N get bigger , he found it was too difficult for him to solve.
Well , you clever ACMers ,could you help little Teddy to solve this problem and let him have a good dream ?
Input
The first line contain a T(T <= 2000) . followed by T lines ,each line contain an integer N (0<=N <= 10 10).
Output
For each case, output the number of ways in one line.
Sample Input
2 1 3
Sample Output
0 1
该题确实在个简单的问题,因为可能形式很简单,但它又不是那么的简单。
如果这个题选择有两个for循环来写的话,那毫无疑问将超时,所以需要仔细分析一下,可以看出,N=i*j+i+j可以变形为:N+1=( i+1)*( j+1),且由 0<i<=j,可知:1<( i+1)<=( j+1),所以就以(i+1)为基准来进行循环,所以只需要单层循环即可。
再有,由于要考虑它的重复性,所以循环只需要进行到sqrt(N+1)即可,往后再循环的必重复。本题 i 要从1开始,所以 i+1 就要从2开始循环,一直到sqrt(N+1)(其实可以等于sqrt( N+1),此时 i=j,符合题意)。
当我想到这一步,我就感觉很明了了,易知(j+1)=( N+1)/(i+1),所以在循环里我用的判断是:if(((N+1)/(i+1))*( i+1)==n+1)
真不知道当时怎么短路了,会去这样判断,还是超时,后来到网上一看,才知道改成:if((N+1)%(i+1)==0)就行了,就解决了超时的问题。
耗时2562ms。
代码如下:
#include <stdio.h> #include <string.h> #include <math.h> typedef __int64 int64; int main() { int64 i,j,n,count,t,k; scanf("%d",&t); while(t--) { count=0; scanf("%I64d",&n); k=sqrt(n+1); for(i=2;i<=k;i++)<span style="white-space:pre"> </span>//这里的i指的是i+1 if((n+1)%i==0) count++; printf("%d\n",count); } return 0; }
其实我还想到了能够进一步优化,先看:
①:奇 * 奇 + 奇 + 奇 = 奇
②:偶 * 偶 + 偶 + 偶 = 偶
③:奇 * 偶 + 奇 + 偶 = 奇
故可得,若 N 为偶数,那 i 和 j 也都是偶数,那 i+1就是从3开始,每次增加2,所以只需判断一下N是不是偶数就行了:
if(n%2==0) { for(i=3;i<=k;i+=2) if((n+1)%i==0) count++; }
那么全代码是:
#include <stdio.h> #include <string.h> #include <math.h> typedef __int64 int64; int main() { int64 i,j,n,count,t,k; scanf("%d",&t); while(t--) { count=0; scanf("%I64d",&n); k=sqrt(n+1); if(n%2==0) { for(i=3;i<=k;i+=2) if((n+1)%i==0) count++; } else { for(i=2;i<=k;i++) if((n+1)%i==0) count++; } printf("%d\n",count); } return 0; }
这样写,耗时会从上面的 2562ms 降到 1859ms,还行吧。
HDU2601,An easy problem