您的位置:首页 > 其它

bzoj 1257: [CQOI2007]余数之和sum

2016-03-28 22:12 323 查看

1257: [CQOI2007]余数之和sum

Time Limit: 5 Sec  Memory Limit:
162 MB
Submit: 3145  Solved: 1450

[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

5 3

Sample Output

7

HINT

50%的数据满足:1<=n, k<=1000 100%的数据满足:1<=n ,k<=10^9

题解:自己想了好久,稍微有点思路,单一直WA,最后才知道,没考虑好,直接暴力不行,我们发现一个数在除于一个连续的数列时(取整),总会有一些商是相等的,而且进行取余时得到的结果是等差数列!例如:10/4,10/5;11/4,11/5;

这样我们可以按照商对连续数列的进行分组(商相同的在一个组里面),

根据:等差数列的性质  Sn=n(a1+an)/2;进行运算!

具体看 AC code 
#include<stdio.h>
#define ll long long
ll min(ll a,ll b)
{
return a>b?b:a;
}
int main()
{
ll n,k;
while(scanf("%lld%lld",&n,&k)!=EOF)
{
ll sum=0;
ll now=2,left,right,xnum,sumlr,t1,extranum,extrasumlr,extra;
while(now<=min(n,k))
{
left=now;//该等差数列的最小一项值 a1;
t1=k/now;
right=k/t1; //该等差数列的最大一项值 an;
sumlr=k%left+k%right; //a1+an
xnum=right-left+1;//n项
sum+=(sumlr*xnum)/2;//Sn=n(a1+an)/2
if(right>n)//当超出规定的界限时,进行超出数列的减
{
extrasumlr=k%(n+1)+k%right;//从超出的第一项An+1到最大的项
extranum=right-n;//超出的项数
extra=(extrasumlr*extranum)/2;//Sn=n(a1+an)/2
sum-=extra;
}
now=right+1;
}
if(n>k)
sum+=(n-k)*k;
printf("%lld\n",sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息