1. 程式人生 > >寒武紀第一屆ACM金牌訓練營網路測試賽 C題 math

寒武紀第一屆ACM金牌訓練營網路測試賽 C題 math

傳送門Math

題目大意:

對於一個數對 (a,b),如果滿足 a%b=a/b,則稱這個數對為“好的數對”。  如果 a<=n, b<=n,那麼有多少對數對是“好的數對”呢? (n<=1e9)

輸入樣例:

5

8

3

65

498

513

115

10

80

100

輸出樣例:

3

7

1

131

1556

1611

268

10

172

227

思路:

這個題算是個找規律的題,我們可以寫出滿足條件的前幾項,發現有下表所示規律:


最左側紅色的是 a%b的餘數,其他帶括號的數對的格式為 (a,b),我們發現第一行數對都是 (a,a-1) 的格式;同一列的 b 都是相同的,且從上到下 a 遞增,每次增加的數也相同就是本列最上面的 a 的值。同一行中的餘數相同,且 a 也是遞增的,每次增加的數是這一行的餘數。

此外,第 i 列的數對個數比第 i-1 列多 1.

然後我們來分析一下題目, n 最大為 1e9,時間限制為 1s,大約有 100 組測試樣例,也就是說時間複雜度要小於 O(n).我一開始 for迴圈是按列來的,但是超時了,因為這樣 n 的值沒有減小,後來改成按行來,由於 a%b 的餘數值一定小於 n ,所以大大降低了時間複雜度。這樣只需要確定每行符合條件的數有多少個就可以了。

程式碼:

#include<stdio.h>
typedef long long LL;
int main()
{
	int i,n,x;
	LL ans;
	while(~scanf("%d",&n))
	{
		ans=0;
		for(i=1;i<=n;i++)
		{ //按行掃描 
			//每行第一個 a 的值為 i*(i+2) 
			if(n<i*(i+2)) break; //如果當前行沒有符合條件的了則退出 
			x=(n-i*(i+2))/i+1; //計算當前行滿足條件的數對的個數 
			ans+=x;
		}
		printf("%lld\n",ans); //注意用 long long 
	}
	return 0;
}