《P2257 YY的GCD》

题目就是求解:$sum_{i = 1}^{n}sum_{j = 1}^{m}|gcd(i,j) = prime|$

显然先枚举素数。这里我们定义P为素数集。

即$ans = sum_{depsilon P}^{}sum_{i = 1}^{n}sum_{j = 1}^{m}|gcd(i,j) = d|$

变换一下得$ans = sum_{depsilon P}^{}sum_{i = 1}^{[frac{n}{d}]}sum_{j = 1}^{[frac{m}{d}]}|gcd(i,j) = 1|$

将$|gcd(i,j) = 1|$用莫比乌斯函数替换得:$ans = sum_{depsilon P}^{}sum_{i = 1}^{[frac{n}{d}]}sum_{j = 1}^{[frac{m}{d}]}sum_{t | gcd(i,j)}^{}mu (t)$

改为枚举t得$ans = sum_{depsilon P}^{}sum_{t = 1}^{min(frac{n}{d},frac{m}{d})}[frac{n}{dt}] * [frac{m}{dt}] * mu (t)$

但是到了这里依旧不够快,我们设T = dt。

那么$ans = sum_{depsilon P}^{}sum_{frac{T}{d} = 1}^{min(frac{n}{d},frac{m}{d})}[frac{n}{T}] * [frac{m}{T}] * mu (frac{T}{d})$

上下界都乘上d,得$ans = sum_{depsilon P}^{}sum_{T = 1}^{min(n,m)}[frac{n}{T}] * [frac{m}{T}] * mu (frac{T}{d})$

然后变形得$ans = sum_{T = 1}^{min(n,m)}[frac{n}{T}] * [frac{m}{T}] * sum_{depsilon P}^{} mu (frac{T}{d})$

观察前半部分,显然是一个整除分块。

那么关于后半部分,考虑一下怎么求解。

我们这里一开始枚举了T,因为T = dt,所以T肯定是d的倍数。

即对于每个T,都要加上T除以它的因数的莫比乌斯函数值。

那么,我们一开始都处理出每个T的这个总值即可,然后处理一个前缀和。

这里的前缀和,是因为我们枚举块的时候,块的位置就是T的改变值,那么我们直接可以前缀和O(1)求出块的后半部分值。

这里的分块,对于每个块里得n/T * m/T都是一样的,然后我们乘上了前缀和的后半部分值,所以是不需要乘上块的大小的。(自己好好理解.

还有这里longlong来跑n.m会T,int就能AC,据说int速度是longlong的1 / 4。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<double,int> pii;
const int N = 1e7+5;
const int M = 1e6+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e18
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;

int mu[N],prime[N],tot = 0;
bool vis[N];
LL f[N],sum[N];
void init()
{
    mu[1] = 1;
    for(rg int i = 2;i < N;++i)
    {
        if(!vis[i])
        {
            prime[++tot] = i;
            mu[i] = -1;
        }
        for(rg int j = 1;j <= tot && i * prime[j] < N;++j)
        {
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;
            else mu[i * prime[j]] = -mu[i];
        }
    }
    for(rg int i = 1;i <= tot;++i)
        for(rg int j = 1;j * prime[i] < N;++j) f[j * prime[i]] += mu[j];
    for(rg int i = 1;i < N;++i) sum[i] = sum[i-1] + f[i];
}
LL cal(int n,int m)
{
    LL ans = 0;
    for(int L = 1,r = 0;L <= min(n,m);L = r + 1)
    {
        r = min(n / (n / L),m / (m / L));
        ans += 1LL * (n / L) * (m / L) * (sum[r] - sum[L - 1]);
    }
    return ans;
}
int main()
{
    init();
    int ca;ca = read();
    while(ca--)
    {
        LL n,m;n = read(),m = read();
        printf("%lld
",cal(n,m));
    }
    //system("pause");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/13825208.html