杜教筛———神奇狄利克雷卷积———欧拉函数

杜教筛———神奇狄利克雷卷积———欧拉函数

Problem Description
One day, Master oy created a new function to celebrate his becoming a ‘huntian’ in majsoul.  

f(n,a,b)=ni=1ij=1gcd(iaja,ibjb)[gcd(i,j)=1]%(109+7) 

Given n, a and b, Master oy wanted Newbie jj who was still a ‘chuxin’ to answer the value of f(n,a,b).

 

Input
There are multiple test cases.

The first line contains an integer T, indicating the number of test cases.

For each test case, there are three positive integers n, a and b which are separated by spaces. It’s guaranteed that a and b are coprime.

1n,a,b109

T=104, but there are only 10 test cases that n is over 106.

 

Output
For each test case, an integer in one line representing your answer.

 

Sample Input
2
1 2 3
100 2 3

 

Sample Output
0
101542
题意:求这个式子的值,通过写了几个互质的数观察,发现gcd那一坨等于i-j;然后打了一个表,第二个样例就是这样,于是与a,b无关。然后又打了一个表观察,发现的确有点规律,go on,感觉与欧拉函数有关,打个表,结论出来f(n)=f(n-1)+p(n)*n/2;(p为欧拉函数),于是转化为求f(n)=∑p(n)*n/2;话是这么说,可是隐隐感觉有写不对,于是把2乘过去,f(n)=f(n-1)+p(n)*n;
f(n)=∑p(n)*n-1;(f(1)=1;),于是先求f(n)=∑p(n)*n;
进入正题—– 杜教筛+狄利克雷卷积     再加一个链接    积性函数前缀和
官方题解为::::::

卷积之后为:f(n) = ∑i²-∑i*f(n/i);(后面需要能够整除),于是代码

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int Mod = 1e9+7;
const int maxn=1e6+10;
LL f[maxn];
LL Prime[maxn];
LL S[maxn];
bool vis[maxn];
int tot;
int n,a,b;
void init(){
    f[1]=1;
    int N=maxn-1;
    for(int i=2;i<=N;i++){
        if(!vis[i]){
            Prime[tot++]=i;
            f[i]=i-1;
        }
        for(int j=0;j<tot;j++){
            if(i*Prime[j]>N){
                break;
            }
            vis[i*Prime[j]]=true;
            if(i%Prime[j]==0){
                f[i*Prime[j]]=f[i]*Prime[j];
                break;
            }
            else {
                f[i*Prime[j]]=f[i]*f[Prime[j]];
            }
        }
    }
    S[1]=1;
    for(int i=2;i<=N;i++) {
        S[i]=(S[i-1]+1ll*f[i]*i%Mod)%Mod;
    }
}

LL qpow(LL a,LL b) {
    LL ans=1;
    while (b) {
        if(b&1) ans=ans*a%Mod;
        a=a*a%Mod;
        b/=2;
    }
    return ans;
}
map<int,LL>Sum;
LL inv6 = qpow (6,Mod-2);
LL GGG(LL n) {
    if(n<maxn) return S[n];
    if(Sum[n]) return Sum[n];
    LL ans=1ll*n*(n+1)%Mod*(2*n+1)%Mod*inv6%Mod;
    LL i,j;
    for(i=2;i<=n;) {
        j=n/(n/i);
        //整除的一坨是连续的一些正整数,就是卷了之后有i,所以是下面
        ans=(ans+Mod-((j+1)*j/2-1ll*i*(i-1)/2)%Mod*GGG (n/i)%Mod)%Mod;
        i=j+1;
    }
    return  Sum[n]=ans;;
}
int main () {
    init ();
    int qwq;
    scanf ("%d",&qwq);
    while (qwq--) {
        scanf ("%d%d%d",&n,&a,&b);
        LL ans=(GGG (n)-1+Mod)%Mod*qpow (2,Mod-2)%Mod;
        printf("%lld\n",ans);
    }
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值