寒武纪第一届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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值