Luogu4240 毒瘤之神的考验

https://www.luogu.com.cn/problem/P4240

参考blog

欧拉函数/莫比乌斯反演

结论:

\[\varphi(ij)=\frac{\varphi(i)\varphi(j)\gcd(i,j)}{\varphi(\gcd(i,j))} \]

证明见此处

正常操作之后,得到这样一个式子

\[Ans=\sum_{T=1}^n(\sum_{d|T} \frac{d}{\varphi(d)} \mu(\frac{T}{d}))(\sum_{i=1}^{\lfloor \frac{n}{T} \rfloor } \varphi(iT))(\sum_{j=1}^{\lfloor \frac{m}{T} \rfloor } \varphi(jT))\\ 令f(n)=\sum_{d|n} \frac{d}{\varphi(d)} \mu(\frac{n}{d}),g(T,n)=\sum_{i=1}^n \varphi(iT)\\ Ans=\sum_{T=1}^n f(T)g(T,\lfloor \frac{n}{T} \rfloor)g(T,\lfloor \frac{m}{T} \rfloor) \]

我们预处理一部分数据,再暴力枚举其他数据(类似根号优化)

\(C++ Code:\)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<vector>
#define N 100000
#define T 10000
#define B 50
#define ll long long
#define mod (long long)998244353
#define int long long
using namespace std;
int cnt,prime[N+5],phi[N+5],mu[N+5],f[N+5];
int T_T,n,m,b,l,r,x,y;
ll ans,inv[N+5],u[N+5];
bool pri[N+5];
vector<ll>g[N+5],t[B+5][B+5];
void Pre()
{
    inv[1]=1;
    for (int i=2;i<=N;i++)
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    phi[1]=mu[1]=1;
    for (int i=2;i<=N;i++)
    {
        if (!pri[i])
        {
            prime[++cnt]=i;
            phi[i]=i-1,mu[i]=-1;
        }
        for (int j=1;j<=cnt;j++)
        {
            ll g=(ll)i*prime[j];
            if (g>N)
                break;
            pri[g]=true;
            if (i%prime[j]==0)
            {
                phi[g]=phi[i]*prime[j];
                mu[g]=0;
                break;
            }
            phi[g]=phi[i]*phi[prime[j]];
            mu[g]=mu[i]*mu[prime[j]];
        }
    }
    for (int i=1;i<=N;i++)
        u[i]=(ll)i*inv[phi[i]]%mod;
    for (int i=1;i<=N;i++)
        for (int j=1;j*j<=i;j++)
            if (i%j==0)
            {
                f[i]=(f[i]+u[j]*mu[i/j])%mod;
                if (j^(i/j))
                    f[i]=(f[i]+u[i/j]*mu[j])%mod;
                f[i]=(f[i]%mod+mod)%mod;
            }
    for (int i=1;i<=N;i++)
    {
        int len=N/i;
        for (int j=1;j<=len+1;j++)
            g[i].push_back(0);
        for (int j=1;j<=len;j++)
            g[i][j]=(g[i][j-1]+phi[i*j])%mod;
    }
    for (int i=1;i<=B;i++)
        for (int j=i;j<=B;j++)
        {
            int len=N/j;
            for (int k=1;k<=len+1;k++)
                t[i][j].push_back(0);
            for (int k=1;k<=len;k++)
                t[i][j][k]=(t[i][j][k-1]+f[k]*g[k][i]%mod*g[k][j]%mod)%mod;
        }
}
signed main()
{
    Pre();
    scanf("%lld",&T_T);
    while (T_T --> 0)
    {
        scanf("%lld%lld",&n,&m);
        if (n>m)
            swap(n,m);
        ans=0;
        for (l=1;l<=n;l=r+1)
        {
            x=n/l,y=m/l;
            r=min(n/x,m/y);
            if (m/l<=B)
                ans=(ans+t[x][y][r]-t[x][y][l-1])%mod; else
                {
                    for (int i=l;i<=r;i++)
                        ans=(ans+f[i]*g[i][x]%mod*g[i][y]%mod)%mod;
                } 
        }
        ans=(ans%mod+mod)%mod;
        cout << ans << endl;
    }
    return 0;
}
posted @ 2020-07-23 08:17  GK0328  阅读(104)  评论(0编辑  收藏  举报