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

版权声明:若希望转载,在评论里直接说明即可,谢谢! https://blog.csdn.net/SSL_ZYC/article/details/86628190

题目大意:

题目链接:

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

给定 x , y x,y ,求
i = 1 y x % 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

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

猜你喜欢

转载自blog.csdn.net/SSL_ZYC/article/details/86628190