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

      

  • 相关阅读:
    判断文件是否存在
    peewee模块更改数据-sqlite
    Python操纵数据库:peewee
    PyQt5调用主窗口
    FHQ-Treap学习笔记
    P3047 [USACO12FEB]Nearby Cows G(树形DP)
    P2986 [USACO10MAR]Great Cow Gathering G(树形DP)
    【普及】Codeforces Round #713(Div 3) 1512A~G
    P1272.重建道路(树形背包)
    P273.有线电视网(树上背包)
  • 原文地址:https://www.cnblogs.com/YMY666/p/8149228.html
Copyright © 2020-2023  润新知