bzoj3309: DZY Loves Math【莫比乌斯反演+积性函数】

本文介绍了一种高效算法来解决特定数学问题:计算正整数范围内所有数对的最大质因数幂次的累加和。通过巧妙地转换问题形式并利用数论中的性质,实现了对大规模数据的有效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

对于正整数n,定义f(n)为n所含质因子的最大幂指数。例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0。
给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b)。

Input

第一行一个数T,表示询问数。
接下来T行,每行两个数a,b,表示一个询问。

Output

对于每一个询问,输出一行一个非负整数作为回答。

Sample Input

4

7558588 9653114

6514903 4451211

7425644 1189442

6335198 4957

Sample Output
35793453939901

14225956593420

4332838845846

15400094813

HINT

【数据规模】

T<=10000

1<=a,b<=10^7

解题思路:

i=1nj=1mf(gcd(i,j)∑i=1n∑j=1mf(gcd(i,j)
=df(d)i=1nj=1m[gcd(i,j)=d]=∑df(d)∑i=1n∑j=1m[gcd(i,j)=d]
=df(d)i=1ndj=1md[gcd(i,j)=1]=∑df(d)∑i=1⌊nd⌋∑j=1⌊md⌋[gcd(i,j)=1]
=df(d)i=1ndj=1mdp|i,p|jμ(p)=∑df(d)∑i=1⌊nd⌋∑j=1⌊md⌋∑p|i,p|jμ(p)
=df(d)pμ(p)i=1npdj=1mpd=∑df(d)∑pμ(p)∑i=1⌊npd⌋∑j=1⌊mpd⌋
=Ti=1nTj=1mTd|Tμ(d)f(Td)=∑T∑i=1⌊nT⌋∑j=1⌊mT⌋∑d|Tμ(d)f(Td)

g(x)=d|xμ(d)f(xd)g(x)=∑d|xμ(d)f(xd),考虑如何快速求g(x)g(x)

首先g(1)=0g(1)=0,否则设x=isptiititi+1x=∏ispiti,ti≤ti+1,那么

g(x)=c1=0t1c2=0t2...cs=0tsμ(pcii)f(pticii)g(x)=∑c1=0t1∑c2=0t2...∑cs=0tsμ(∏pici)f(∏piti−ci)
g(x)=c1=01c2=01...cs=01μ(pci=0i)f(pticii)g(x)=∑c1=01∑c2=01...∑cs=01μ(∏pici=0)f(∏piti−ci)

t1<tst1<ts,则
g(x)=c2=01...cs=01μ(pcii)f(pt11pticii)+g(x)=∑c2=01...∑cs=01μ(∏pici)f(p1t1∏piti−ci)+
c2=01...cs=01μ(p1pcii)f(pt111pticii)∑c2=01...∑cs=01μ(p1∏pici)f(p1t1−1∏piti−ci)
=c2=01...cs=01μ(pcii)f(pt11pticii)=∑c2=01...∑cs=01μ(∏pici)f(p1t1∏piti−ci)−
c2=01...cs=01μ(pcii)f(pt111pticii)=0∑c2=01...∑cs=01μ(∏pici)f(p1t1−1∏piti−ci)=0

否则t1=t2=...=tst1=t2=...=ts
g(x)=ci1μ(pcii)t1+μ(pi)(t11)g(x)=∑∏ci≠1μ(∏pici)t1+μ(∏pi)(t1−1)
=c1=01c2=01...cs=01μ(pcii)t1μ(pi)=∑c1=01∑c2=01...∑cs=01μ(∏pici)t1−μ(∏pi)
=i=0s(1)iCisμ(pi)=∑i=0s(−1)iCsi−μ(∏pi)
=μ(pi)=(1)s+1=−μ(∏pi)=(−1)s+1

这样就很好筛了,记录每个数最小质因数的幂数t(x)t(x)即除掉所有最小质因数后的数last(x)last(x)即可。

时间复杂度为O(nTn)O(n−Tn)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=10000005;
int pn,pri[N],t[N],last[N],g[N];
void sieve()
{
    for(int i=2;i<N;i++)
    {
        if(!t[i])pri[++pn]=i,t[i]=last[i]=g[i]=1;
        for(int j=1;j<=pn;j++)
        {
            ll k=i*pri[j];
            if(k>=N)break;
            if(i%pri[j]==0)
            {
                last[k]=last[i];
                t[k]=t[i]+1;
                if(last[k]==1)g[k]=1;
                else g[k]=t[k]==t[last[k]]?-g[last[k]]:0;
                break;
            }
            last[k]=i,t[k]=1,g[k]=(t[i]==1?-g[i]:0);
        }
    }
    for(int i=2;i<N;i++)g[i]+=g[i-1];
}
ll F(int n,int m)
{
    ll res=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));
        res+=1ll*(n/i)*(m/i)*(g[j]-g[i-1]);
    }
    return res;
}
int main()
{
    //freopen("lx.in","r",stdin);
    sieve();
    for(int T=getint();T;T--)
    {
        int n=getint(),m=getint();
        printf("%lld\n",F(n,m));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值