[清华集训2012](洛谷2260)模积和

Posted Kananix

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[清华集训2012](洛谷2260)模积和相关的知识,希望对你有一定的参考价值。

传送门:here

一句话题意:求$ \sum\limits_{i=1}^n\sum\limits_{j=1}^m(n\ mod\ i)(m\ mod\ j)$,$ i \neq j$

简化题意:                                                                                          

假设$ n<m$

我们令$ f(x)$表示$ \sum\limits_{i=1}^x\ x\ mod\ i$,$ f2(x,y)$表示$ \sum\limits_{i=1}^n(n\ mod\ i)(m\ mod\ i)$

则原式可化简为$ f(n)f(m)-f2(n,m)$

 

考虑求$ f(x)$                                                                                         

发现这是经典的余数求和问题 原题:here

基于数论分块,当$ i \leq x$时,$ \left\lfloor\frac{x}{i}\right\rfloor$最多只有$ 2*\sqrt{x}$种取值

因此我们枚举所有可能的值,发现在$ \left\lfloor\frac{x}{i}\right\rfloor$相同时余数是一个公差为$ \left\lfloor\frac{x}{i}\right\rfloor$的降序等差数列

直接求和即可

 

考虑求$ f2(n,m)$                                                                               

不难发现依旧是数论分块的模型

根据求$ f$的经历可以发现我们要做的是两个等差数列每一项的乘积之和

我们令数论分块的某一时刻公差$ \left\lfloor\frac{n}{i}\right\rfloor$为$ a$,$ \left\lfloor\frac{m}{i}\right\rfloor$为$ b$,项数为$ num+1$,首项分别为$ x$和$ y$

则可令第一个等差数列为$ [x],[x-a],[x-2*a] ... [x-num*a]$,

第二个等差数列为$ [y],[y-b],[y-2*b] ... [y-num*b]$

乘积结果为

$ [xy] + [xy-(ay+bx)+ab]+[xy-2(ay+bx)+4ab]+...+[xy-num(ay+bx)+num^2ab]$

即$ (num+1)*xy-\frac{num*(num+1)}{2}*(ay+bx)+\frac{num*(num+1)*(2*num+1)}{6}*ab$

需要注意的是模数不是质数不能用费马求逆元

然后就可以愉快的计算了

 

code:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rt register int
#define ll long long
#define r read()
#define p 19940417
#define inv2 9970209
#define inv6 3323403
using namespace std;
ll read()
{
    ll x = 0; int zf = 1; char ch;
    while (ch != - && (ch < 0 || ch > 9)) ch = getchar();
    if (ch == -) zf = -1, ch = getchar();
    while (ch >= 0 && ch <= 9) x = x * 10 + ch - 0, ch = getchar(); return x * zf;
}
void write(ll y)
{
    if (y < 0) putchar(-), y = -y;
    if (y > 9) write(y / 10);
    putchar(y % 10 + 0);
}
inline void writeln(ll x)
{
    write(x);putchar(\n);
}
int i,j,k,m,n,x,y,z,cnt,all,num;
ll f(const int x)//余数求和 
{
    ll ans=0;
    for(rt i=1;i<=x;)
    {
        const int R=x/(x/i);
        ans+=(ll)(x%i+x%R)*(R-i+1)>>1;
        ans%=p;i=R+1;
    }
    return ans%p;
}
ll calc(const int x,const int y,const ll a,const int b,const int num)//计算贡献 
{
    ll ans=(ll)x*y%p*num%p;
    ll sum=(ll)num*(num-1)/2;sum%=p;
    ans=ans-sum*((a*y+b*x)%p)%p;
    const ll sum2=(ll)num*(num-1)%p*(2*num-1)%p*inv6%p;
    ans=(ans+sum2*a%p*b+p)%p; 
    return ans;
}
int getv(const int x,const int y)//数论分块计算答案 
{
    ll ans=0;
    for(rt i=1;i<=x;)
    {
        const int R1=x/(x/i),R2=y/(y/i);
        const int s=min(R1,R2);
        ans+=calc(x%i,y%i,x/i,y/i,s-i+1); 
        i=s+1;
    }
    return ans%p;
}
int main()
{
    n=r;m=r;if(n>m)swap(n,m);
    writeln((f(n)*f(m)%p+p-getv(n,m))%p);
    return 0;
}

 

以上是关于[清华集训2012](洛谷2260)模积和的主要内容,如果未能解决你的问题,请参考以下文章

P2260 [清华集训2012]模积和

P2260 [清华集训2012]模积和(整除分块)

BZOJ2956模积和 分块

BZOJ_2956_模积和_数学

[BZOJ 2956]模积和

模积和(bzoj 2956)