zoukankan      html  css  js  c++  java
  • 【bzoj1257】[CQOI2007]余数之和sum 数论

    题目描述

    给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

    输入

    输入仅一行,包含两个整数n, k。

    输出

    输出仅一行,即j(n, k)。

    样例输入

    5 3

    样例输出

    7


    题解

    分块

    首先当i>k时,k%i=k,所以如果n>k,直接把答案预先加上(n-k)*k,再把n变成k计算即可。

    然后就是求 ∑(k%i)(1≤i≤n) 的问题。

    考虑到 k%i=k-i*(k/i) ,于是所求即为∑(k-i*(k/i))(1≤i≤n) = n*k-∑(i*(k/i))(1≤i≤n) 。

    这里注意到对于某一个k/i=x的x,能够满足条件i必然是连续的一段。

    那么就可以分块来做。

    对于每个i=last+1,总有last'=min(n,k/(k/i)),满足在且仅在[i,last']区间内的值j符合k/j=k/i。

    然后用一下等差数列求和公式快速求出i~last'的和,再乘上k/i加到答案中即可。

    #include <cstdio>
    #define min(a , b) a < b ? a : b;
    int main()
    {
    	long long n , k , i , last , ans = 0;
    	scanf("%lld%lld" , &n , &k);
    	if(n > k) ans = (n - k) * k , n = k;
    	ans += n * k;
    	for(i = 1 ; i <= n ; i = last + 1)
    	{
    		last = min(n , k / (k / i));
    		ans -= (k / i) * (i + last) * (last - i + 1) / 2;
    	}
    	printf("%lld
    " , ans);
    	return 0;
    }

     

  • 相关阅读:
    【转】java内存溢出的场景及解决办法
    系统架构
    【转】Linux tar命令详解
    【转】Java 开发必会的 Linux 命令
    【转】ps命令详解与使用
    【转】Linux命令:ps -ef |grep java
    linux grep命令详解
    【springcloud】Zuul 超时、重试、并发参数设置
    【springcloud】常见面试题总结
    php的函数应用
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6556418.html
Copyright © 2011-2022 走看看