码迷,mamicode.com
首页 > 其他好文 > 详细

P2261 [CQOI2007]余数求和

时间:2017-10-14 23:25:23      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:nbsp   names   class   输出   ast   输入格式   logs   pre   algorithm   

题目描述

给出正整数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

 

输出格式:

 

答案

 

输入输出样例

输入样例#1:
10 5
输出样例#1:
29

说明

30%: n,k <= 1000

60%: n,k <= 10^6

100% n,k <= 10^9

 

题解:

这差不多是道数学题吧

看样例发现对与n大于k的的部分,k模它的余数一定为k

那么只需考虑k以内的了

k%x可以写成k=a*x+r,模出来的值其实就是r

我想,当x与k很接近时,当x增大时a基本上变化很小。在确定a不变的情况下r随x增加而发生的变化是很好计算的,就是个等差数列嘛!

而显然若a能基本不变那么a一定很小,其小于大的分界线便是sqrt(n)

如果不太理解可以自己试试数算一下,比如48、49之类的

对于a>sqrt(n),也就是x<sqrt(n)时,可以枚举x求余数和

之后便从sqrt(n)到1枚举a,由于在a不变时余数就是个等差数列,那么知道数列的个数与首项、公差就可以求和了。公差由k=a*x+r可知就是a

之后就可以了,这题的细节有点多,需要注意一下

 

总结一下思路:
发现只需考虑k以内的 -> 由余数想到除,由除想到反比例函数增长快慢sqrt(n)可做分界线 -> 分类讨论发现余数的规律 -> 注意细节进行计算

 

代码:

技术分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 int n,k;
 9 ll ans=0;
10 
11 int main()
12 {
13     int i,m,w,x,y,last;
14     scanf("%d%d",&n,&k);
15     if(n>k) ans+=(ll)(n-k)*k;
16     
17     m=sqrt(k);y=k/m;
18     for(i=1;i<=y && i<=n;i++)
19         ans+=k%i;
20     last=y;
21     for(i=m-1;i>0;i--){
22         w=k/i;
23         x=k%(last+1);
24         if(w<n) ans+=(ll)(w-last)*(x+x-(w-last-1)*i)/2;
25         else{
26             ans+=(ll)(n-last)*(x+x-(n-last-1)*i)/2;
27             break;     
28         }
29         last=w;
30     }
31     printf("%lld",ans);
32 
33     return 0;    
34 }
View Code

 

P2261 [CQOI2007]余数求和

标签:nbsp   names   class   输出   ast   输入格式   logs   pre   algorithm   

原文地址:http://www.cnblogs.com/lindalee/p/7668889.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!