【洛谷】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; }