【JZOJ3812】【洛谷P2261】余数求和【数论,数学】【规律】

题目大意:

题目链接:

洛谷:https://www.luogu.org/problemnew/show/P2261
JZOJ:https://jzoj.net/senior/#main/show/3912

给定x,yx,y,求
i=1yx%i\sum^{y}_{i=1}x\%i


思路:

首先暴力打个表。

1- 0
2- 0 0
3- 0 1 0
4- 0 0 1 0
5- 0 1 2 1 0
6- 0 0 0 2 1 0
7- 0 1 1 3 2 1 0
8- 0 0 2 0 3 2 1 0
9- 0 1 0 1 4 3 2 1 0
10- 0 0 1 2 0 4 3 2 1 0
11- 0 1 2 3 1 5 4 3 2 1 0
12- 0 0 0 0 2 0 5 4 3 2 1 0
13- 0 1 1 1 3 1 6 5 4 3 2 1 0
14- 0 0 2 2 4 2 0 6 5 4 3 2 1 0
15- 0 1 0 3 0 3 1 7 6 5 4 3 2 1 0
16- 0 0 1 0 1 4 2 0 7 6 5 4 3 2 1 0
17- 0 1 2 1 2 5 3 1 8 7 6 5 4 3 2 1 0
18- 0 0 0 2 3 0 4 2 0 8 7 6 5 4 3 2 1 0
19- 0 1 1 3 4 1 5 3 1 9 8 7 6 5 4 3 2 1 0
20- 0 0 2 0 0 2 6 4 2 0 9 8 7 6 5 4 3 2 1 0
21- 0 1 0 1 1 3 0 5 3 1 10 9 8 7 6 5 4 3 2 1 0
22- 0 0 1 2 2 4 1 6 4 2 0 10 9 8 7 6 5 4 3 2 1 0
23- 0 1 2 3 3 5 2 7 5 3 1 11 10 9 8 7 6 5 4 3 2 1 0
24- 0 0 0 0 4 0 3 0 6 4 2 0 11 10 9 8 7 6 5 4 3 2 1 0
25- 0 1 1 1 0 1 4 1 7 5 3 1 12 11 10 9 8 7 6 5 4 3 2 1 0
26- 0 0 2 2 1 2 5 2 8 6 4 2 0 12 11 10 9 8 7 6 5 4 3 2 1 0
27- 0 1 0 3 2 3 6 3 0 7 5 3 1 13 12 11 10 9 8 7 6 5 4 3 2 1 0
28- 0 0 1 0 3 4 0 4 1 8 6 4 2 0 13 12 11 10 9 8 7 6 5 4 3 2 1 0
29- 0 1 2 1 4 5 1 5 2 9 7 5 3 1 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
30- 0 0 0 2 0 0 2 6 3 0 8 6 4 2 0 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

ii行的第jj个数字表示x=i,y=jx=i,y=j时的答案。(第一列是行标号)。
然后就会发现:
l=[x÷i],r=[x÷(i+1)]l=[x\div i],r=[x\div (i+1)]时,lrl\sim r之间的所有数字被xx除之后的余数是一个公差为ii的等比数列。([][]表示向下取整)
那么可以枚举ii,求出l,rl,r,然后求出项数,最后用等差数列求和公式即可。
但是当x=y=109x=y=10^9时,需要枚举10910^9次,会稳稳超时。
所以当[x÷i]=[x÷(i+1)][x\div i]=[x\div (i+1)]时,剩余的数字在n\sqrt{n}左右,直接推出枚举暴力求解即可。
然后就愉快的拿到8080分。
注意题目没说yxy\leq x,所以当y>xy>x时,直接

if (m>n)
{
	ans+=(m-n)*n;
	m=n;
}

时间复杂度:O(O(玄学)),大约O(x)O(\sqrt{x})吧。


代码:

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;

ll n,m,ans,a1,an,s,k;

int main()
{
	cin>>n>>m;
	if (m>n)
	{
		ans+=(m-n)*n;
		m=n;
	}
	for (ll i=n/m;(n/i)!=(n/(i+1));i++)  //枚举i,判断[x/i]和[x/(i+1)]
	{
		a1=n%min(n/i,m);  //首项
		an=n%(n/(i+1)+1);  //末项
		ans+=(a1+an)*(an-a1+i)/i/2;  //求和公式
		k=n/(i+1)+1;  //记录计算到那个位置
	}
	for (ll i=1;i<k;i++)  //剩余暴力求解
		ans+=n%i;
	cout<<ans<<endl;
	return 0;
}
posted @ 2019-01-24 15:49  全OI最菜  阅读(118)  评论(0编辑  收藏  举报