余数求和 洛谷p2261
来源:互联网 发布:数据的统计 编辑:程序博客网 时间:2024/05/19 16:32
题目描述
给出正整数n和k,计算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod 3 + 5 mod 4 + 5 mod 5 …… + 5 mod 10=0+1+2+1+0+5+5+5+5+5=29
输入输出格式
输入格式:两个整数n k
输出格式:答案
输入输出样例
10 5
29
说明
30%: n,k <= 1000
60%: n,k <= 10^6
100% n,k <= 10^9
根据题目可以写出ans=i=1∑nk%i
首先知道一点 a%b 可以表示为 a−b∗⌊ba⌋,写过高精取模的人应该都知道
所以 ans=i=1∑nk−i∗⌊ik⌋=n∗k−i=1∑ni∗⌊ik⌋
- 然后 ⌊ik⌋ 可以出发分块来做,⌊ik⌋大约有k种取值,所以时间复杂度
O(k)
我实在是太弱,只好去刷水题了。
首先注意到,对于任意一个$1≤i≤k$,⌊ik⌋的取值只有O(k)种,并且相同的⌊ik⌋的取值对应的i都是连续的一段区间。所以,先把所有满足条件的区间提取出来。
对于任意一个⌊ik⌋==⌊i+1k⌋,有:
k=i∗⌊ik⌋+kmodi=(i+1)∗⌊i+1k⌋+kmod(i+1)
设x=⌊ik⌋,a=kmodi,则有:
i∗x+a=(i+1)∗x+kmod(i+1)
化简得a=x+kmod(i+1)。
即对于任意一个⌊ik⌋==⌊i+1k⌋,有kmodi=kmod(i+1)+⌊ik⌋。
也就是说,对于一段区间[l,r],如果⌊lk⌋,⌊l+1k⌋,...,⌊r−1k⌋,⌊rk⌋的值全部相同,则有:
∑i=lrkmodi=(kmodl)∗(r−l+1)−2⌊lk⌋∗(r−l)∗(r−l+1)。
这样就很好做了。具体实现见代码。注意,对于任意一个i>k,kmodi=k。
#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;int main() { ll n,k; scanf("%lld%lld",&n,&k); ll ans=n*k; for(ll l=1,r;l<=n;l=r+1) { if(k/l!=0) r=min(k/(k/l),n); else r=n; ans-=(k/l)*(r-l+1)*(l+r)/2; } printf("%lld",ans); return 0;}
首先,我们处理一下n>=k的情况,因为这种情况很好处理:
G(n,k)=k%1+k%2+......+k%n,那么,当n>=k时,n>=k的部分k%i就是k,然后就是n<k了
这里,我们定义[c]为对c下取整.
我们不难发现在[k/2]+1到k这个区间里,k%i是一个等差数列,公差为1
在[k/3]+1到[k/2]这个区间里,k%i也是一个等差数列,公差为2
在[k/4]+1到[k/3]这个区间里,k%i也是一个等差数列,公差为3
.........
一直到[k/√k]+1到[k/(√k-1)]这个区间里,k%i也是一个等差数列,公差为(√k-1).
剩下的1到[k/√k]的区间直接暴力求解即可.
这样,我们就能用O(√k)来解决了.
再讨论一下比较难想的n<k的情况,
当n<k时,自然就不存在能直接算出k%i的部分了,
有人会问了,这不是更简单一些吗?直接不要超出的部分,再用上面给出的计算不就行了,
是的,大部分是这样,但是,我们需要考虑的是,有可能以上给出的区间中,n并不包含其中,也就是说没必要算那些不包含n的区间了.
那么,我们需要找一个区间,使n包含其中,剩下的都按上面的方法做即可.
long long n,i,k,l,ans;//注意:整型默认为下取整int main(){ cin>>n>>k; if(n>=k){//n>=k的部分 ans=(n-k)*1ll*k;//k%i的结果都是k,共有(n-k)个 } else{//否则n<k for(i=1;i*i<=k&&i<n;i++){//找一个区间使得n在其中,i就是区间上界的分母(详情看解释) if(k/i<n){//找到了 l=k/i;//记下来 break;//退出 } l=i;//否则就是当前的i } l++;//这里l++是为了把分母移到区间的下界(详情看解释) ans=1ll*(n-l+1)*(k%n+k/l*(n-l)+k%n)/2;//注意:这里是特殊处理含n的区间(其中上界是n,下界是l,公差为k/l) //高斯速算公式:(首项+末项)*项数/2 //(n-l+1)相当于项数,也就是区间长度 //k%n是首项 //k/l*(n-l)+k%n是末项,因为公差是k/l,中间有(n-l)个数,首项是k%n } for(i=k/n+1;i*i<=k;i++){//两种情况的交集,也就是都需要枚举,一开始i=k/n+1,i<=√k, //这里我们需要一个证明:为什么一开始i=k/n+1,当n>=k时,k/n+1刚好是1,也就是解释里第一个区间的上界分母 //当n<k时,因为刚刚已经处理过了包含n的区间,所以不必再处理,k/n+1刚好是包含n区间的下一个区间的上界分母 ans+=1ll*(k%i+i*(k/i-k/(i+1)-1)+k%i)*(k/i-k/(i+1))/2; //高斯速算公式:(首项+末项)*项数/2 //这里首项是k%i //末项是i*(k/i-k/(i+1)-1)+k%i,因为公差是i,其中一共有k/i-k/(i+1)-1个数,也就是项数-1(详情看解释) //项数是k/i-k/(i+1) } n=k/i;//1到[k/√k]的区间暴力求解 for(i=1;i<=n;i++){ ans+=k%i;//每次ans+k%i } cout<<ans<<endl; //system("pause"); return 0;}好了,做到这儿,是不是觉得很简单了呢?
- 余数求和 洛谷p2261
- 洛谷 P2261 [CQOI2007]余数求和
- 洛谷 P2261 [CQOI2007]余数求和
- 洛谷 P2261 [CQOI2007]余数求和
- 洛谷 P2261 [CQOI2007]余数求和
- 数学-洛谷P2261 [CQOI2007]余数求和
- 洛谷P2261
- 洛谷Oj-余数求和-数学
- BZOJ1257 洛谷2261 [CQOI2007]余数求和
- CQOI2007 余数求和
- [CQOI2007]余数求和
- nyist-508(余数求和)
- 【BZOJ1257】[CQOI2007]余数之和sum【余数求和】【分块】
- NYOJ 508 余数求和 (数论问题)
- 51nod-1225-余数求和(分块)
- [BZOJ1257][CQOI2007]余数求和(数论)
- 【SPOJ-NAGAY】Joseph’s Problem【余数求和】【分块】
- bzoj1257(SPOJ-NAGAY Joseph’s Problem(余数求和))(分块)
- c语言
- Remove Duplicates from Sorted Array
- JS获取DOM节点
- python模块之HTMLParser: 解析html,获取url
- 【codevs 2604】舞会邀请
- 余数求和 洛谷p2261
- Okhttp封装
- 20171102-程序员的自我修养
- WebService
- 数据结构之链表面试题汇总(三)判断单链表是否有环、取出环的起始点、得到有环链表中环的长度
- 第一二章课后习题
- 简单工厂、工厂方法模式和抽象工厂
- 第十周训练总结(一)
- String类的常用方法