【洛谷】P2261 [CQOI2007]余数求和

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,k,l,r,right;
	scanf("%d %d",&n,&k);
	long long ans = (long long)n * k;
	for (int i = 1 ; i <= n ; i = right + 1)
	{
		l = i; r = n ; int  mid;
		int a = k/i;
		while (l <= r)
		{
		    mid = (l+r) / 2;
			if (k/mid == a)
			{
				right = mid;
				l = mid + 1;
			}
			else
			{
				r = mid - 1;
			}
		}
		long long cha = (long long)a * (i+right)*(right-i+1)/2;
		ans -= cha;
	}
	cout<<ans<<endl;
	return 0;
}

这道题的我的思路:(我很弱的,各位大佬多多指导——特别是Srf红名大神)  

易证得:(刘翔的名言)

ans = ∑ i = 1 to n (k mod i) 

则 ans = ∑ i = 1 to n (k - [k/i]*i)  做过高精度取余的大佬们必定知道

所以 ans = n * k - ∑ i = 1 to n ([k/i]*i)

注意到:[k/i]当k一定时,大约只有√k种取值 。 所以 我们可以用二分的方式找到一组 L 和 R , 使得L和R中任意一个i,满足[k/i]相等,这样就不会超时了! 

 

December 31st:

在此特别感谢Srf大佬的指导(帮助小蒟蒻在0ms的时间内AK了!)膜拜大佬!!

思路:如果一段区间L和R满足[k/i]相等,那么下一段同样满足此条件的区间为:[R+1,min(k/(k/i),n)](当k/i != 0时)  (注意:这里的min(…)很重要,因为k有可能 > n,不加上会多减掉一部分(即n+1到k/(k/i)))当 k/i == 0时,太弱智了,自己想吧。。。

 

0ms AK 的代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	long long n,k,l;
	scanf("%lld %lld",&n,&k);
	long long ans = n * k;
	for (long long i = 1 ; i <= n ; i = l + 1)
	{
		long long a = k/i;
		l = (a != 0) ? min(k/a,n) : n;
		long long cha = a * (i+l)*(l-i+1)/2;
		ans -= cha;
	}
	cout<<ans<<endl;
	return 0;
}

  

 

posted @ 2017-12-30 11:39  surpassion  阅读(260)  评论(3编辑  收藏  举报