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

【BZOJ】1257 余数之和

时间:2015-07-24 13:07:12      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:余数   数论   高斯记号   代数变形   bzoj   

[Analysis]
j(n,k)
=∑k mod i, 1<=i<=n
=∑k-[k/i]*i,1<=i<=n
=n*k-∑[k/i]*i,1<=i<=n
当i>k时,[k/i]*i=0。
∴只用考虑i<=k的情况,即:
j(n,k)=n*k-∑[k/i]*i,1<=i<=min(n,k)。

根据性质知道[k/i]的取值个数不超过根号k个。
又易得f(i)=[k/i]的值是下降的,所以即求根号k个连续区间。

用i从1到min(n,k)枚举,每次找到取值w,算出左右区间。
左区间:L=i。
右区间:当[k/i]=w时,
根据高斯消元的性质,w=[k/i]<=k/i,
∴i>=k/w,R=(int)k/w。
∵可能存在R>=n,所以R=min(R,n)。
对于每个区间,res+=w*∑q,L<=q<=R。
然后i=R+1。

最后的res就是结果。

[Sumup]
①两个高斯记号的取值范围的性质。 [] {}
②[k/i]的取值个数不超过根号k个,因此可以从头开始枚举找到这k个值,时间复杂度O(根号k)。
③a mod b = a - [a/b]*b。

[Code]
/**************************************************************
    Problem: 1257
    User: y20070316
    Language: C++
    Result: Accepted
    Time:8 ms
    Memory:804 kb
****************************************************************/
 
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
 
typedef long long LL;
 
int n,m;
LL sum;
 
int main(void)
{   
    scanf("%d%d",&n,&m);
     
    sum+=(LL)n*m;
    if (n>m) n=m;
     
    int l,r,j;
    for (int i=1;i<=n;i=r+1)
    {
        j=m/i,l=m/(j+1)+1,r=m/j;
        if (r>=n) r=n;
        sum-=(LL)(l+r)*(r-l+1)*j/2;
    }
    printf("%lld\n",sum);
     
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

【BZOJ】1257 余数之和

标签:余数   数论   高斯记号   代数变形   bzoj   

原文地址:http://blog.csdn.net/u013598409/article/details/47037031

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