標籤:數論
C - An easy problem
Time Limit:3000MS
Memory Limit:32768KB
64bit IO Format:%I64d & %I64uSubmit Status
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
213
Sample Output
01
該題確實在個簡單的問題,因為可能形式很簡單,但它又不是那麼的簡單。
如果這個題選擇有兩個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+1if((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,還行吧。