• [CQOI2007] 余数求和


    Description

    (sum_{i=1}^n;k;mod;i)

    Solution

    先化简式子
    (sum_{i=1}^n;k;mod;i=sum_{i=1}^nk-lfloor{frac{k}{i}} floor=k imes n-sum_{i=1}^nlfloor{frac{k}{i}} floor)

    用样例打表找规律之后,发现 (lfloor{frac{k}{i}} floor) 分别在一定的区域内相等。

    所以用分块除法来做这题。

    首先定义 (t=lfloor{frac{k}{i}} floor)

    (l) 来代表我们当前除法块的左边界, (r) 来代表右边界,我们让一开始的 (l=1) ,因为第一块除法块的开头永远都是从 (1) 开始,然后我们可以通过 (l) 来求出 (r)

    t=k/l;
    if(!t) break;
    r=std::min(k/t,n);
    

    因为我们的定义是 (t=lfloor{frac{k}{i}} floor)

    所以我们可以直接让 (t=k/l) 来求出他当前除法块的商,因为连续一块除法块的商都是相等的(不相等就绝对不是同一块),这样我们算出了 (t) ,然后就通过 (t) 来找 (l)

    (t=0) 时,(r=n)

    (t!=0) 时,(r=min(lfloor{frac{k}{t}} floor,n))

    解释如下,因为当 (t=0) 时,后面那一块肯定都是大于 (k) 的那一段,所以我们直接让 (r=n) ,算出最后这一大块,当 (t!=0) 的时候,我们让 (r=lfloor{frac{k}{t}} floor),这样可以算出有这个整除的商的最大的一个整数是多少,因为 (lfloor{frac{k}{t}} floor) 可能会大于 (n) ,所以我们加上一个 (min) 函数,防止他超过边界。 有了右边界,每一块的和也就好求了

    剩下的就是用 (n imes k)减去每一块的值就好了

    摘自

    Code

    #include<cstdio>
    #include<iostream>
    #define int long long
    
    int ans;
    int n,k;
    
    signed main(){
    	int r;
    	scanf("%lld%lld",&n,&k);
    	for(int i=1;i<=n;i=r+1){
    		int t=k/i;
    		if(!t) break;
    		r=std::min(k/t,n);
    		ans+=t*(i+r)*(r-i+1)/2;
    		//printf("i=%lld,ans=%lld
    ",i,ans);
    	}
    	printf("%lld
    ",n*k-ans);
    	return 0;
    }
    
  • 相关阅读:
    Hive之安装
    python3常用内置方法(持续更新中。。。)
    CentOS7下安装Python3及Pip3并保留Python2
    一个爬取52破解的全部帖子地址的简单爬虫
    在windows写入文件中遇到 UnicodeEncodeError: ‘gbk’ codec can’t encode character 错误的解决办法
    我的vim配置
    树莓派命令行模式调整音量
    树莓派更改软件源
    linux连接wifi
    给树莓派挂载移动硬盘或U盘
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/9027038.html
Copyright © 2020-2023  润新知