BZOJ2693:JZPTAP——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=2693

Description

 

Input

一个正整数T表示数据组数

接下来T行 每行两个正整数 表示N、M

Output

T行 每行一个整数 表示第i组数据的结果

Sample Input

1
4 5

Sample Output

122

——————————————————————————————————————————

图片和题解参考均来自于https://www.cnblogs.com/GXZlegend/p/7000042.html以其这里面的链接。

推导过程如图:

这里说一下比较不好理解的步骤。

将每一行边号从1开始。

2:只是变成了枚举gcd的取值,然后判断是否应该取即可。

3:i变成了i/p之后自然需要乘p*p,一约分就成了3式子。

以及最后一个fn当中的所有k应当为n。

然后引用上面的博客来求fn:

 

设f1(n)=n2mu(n),f2(n)=n,则显然f2是积性函数,f1为两个积性函数的乘积,也是积性函数。

 

那么f为f1和f2的狄利克雷卷积,也是积性函数。

 

所以可以尝试快筛f(n)。

 

当n为质数时,显然f(n)=n-n^2。

 

当n不为质数时,即n=i*p,p|i,p是质数,那么观察f(n)化简之后的式子,n新增加出来的约数一定是包含p^2的,它的mu值一定是0,所以f(n)的改变只是从i*...变为了n*...,所以此时f(n)=f(i)*p。

 

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=10000010;
const int p=1e8+9;
inline int read(){
    int X=0;char ch=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return X;
}
ll f[N],su[N];
bool he[N];
inline ll s(ll x){
    return x*(x+1)/2%p;
}
void Euler(int n){
    int tot=0;
    f[1]=1;    
    for(int i=2;i<=n;i++){
    if(!he[i]){
        su[++tot]=i;
        f[i]=(ll)((i-(ll)i*i)%p+p)%p;
    }
    for(int j=1;j<=tot;j++){
        if(i*su[j]>n)break;
        he[i*su[j]]=1;
        if(i%su[j]==0){
        f[i*su[j]]=f[i]*su[j]%p;
        break;
        }
        else f[i*su[j]]=f[i]*f[su[j]]%p;
    }
    }
    for(int i=1;i<=n;i++){
    f[i]+=f[i-1];
    if(f[i]>=p)f[i]-=p;
    }
    return;
}   
int main(){
    Euler(10000000);
    int t=read();
    while(t--){
    int n=read(),m=read(),ans=0;
    if(n>m)swap(n,m);
    for(int i=1,j;i<=n;i=j+1){
        j=min(n/(n/i),m/(m/i));
        ans+=(ll)(f[j]-f[i-1])*s(n/i)%p*s(m/i)%p;
        if(ans<0)ans+=p;
        if(ans>=p)ans-=p;
    }
    printf("%d\n",ans);
    }
    return 0;
}
posted @ 2018-01-05 08:57  luyouqi233  阅读(187)  评论(0编辑  收藏  举报