[CQOI2007]余数求和
Posted clockwhite
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2007]余数求和相关的知识,希望对你有一定的参考价值。
[CQOI2007]余数求和
题目链接
题意简述:
给出n,k求k%1~n每一个数的和
解题思路
1.式子变形
首先将原始式子变形成为nk-(k/1*1+k/2*2...k/n*n),此处的除法都是向下取整,也就是说不可以使用运算律了。
2.区间思想
那么我们通过简化式子,得到了一个不能用运算律的式子。此时我们发现不能暴力去算他。于是尝试着找了一会规律,可得到一个表格。(以100为例)
(相同的用颜色标记出来)
如果说颜色是区间的话。那么知道左端点就可以知道右端点。
记左端点为x,右端点为y. y=k/(k/i),注意此处k/i向下取整。
又由于区间与区间是相连的,所以说下一个区间的左端点为这一个区间的右端点加一。
并且第一个区间的左端点为1.由此可以计算出所有的区间。
3.利用区间思想解题&额外补充
1)解题:
将区间思想与式子结合起来。将k/1*1+k/2*2...k/n*n按照区间分开来计算。知道k/i的定值,提取一个k/i的公因数,剩下的x,x+1,x+2...求和。
2)额外补充:
右端点取出来可能大于n,要处理一下。
当n>k的时候,会出现k/i=0的情况,先把后面的累积到答案中,然后切换成n=k的子任务。
代码
#include<bits/stdc++.h> using namespace std; #define ll long long ll n,k,ans; int main(){ cin>>n>>k; if(n>k){ ans=(n-k)*k; n=k; } ll z=1,y=1; while(z<=n){ int x=k/z,num; y=min(n,k/x); num=y-z+1; ans+=num*k-x*((z+y)*num/2); z=y+1; } cout<<ans; return 0; }
以上是关于[CQOI2007]余数求和的主要内容,如果未能解决你的问题,请参考以下文章