Loading

P1447 [NOI2010]能量采集(莫比乌斯反演)

传送门

题意

实际上是求\(\sum\limits^n_{i=1}\sum\limits^m_{j=1}(2gcd(i,j)-1)\)

解题过程

\(=2\sum\limits^n_{i=1}\sum\limits^m_{j=1}gcd(i,j)-nm\)

\(nm\)不关键 我们无视掉继续算

不妨假设\(n<=m\)

\(2\sum\limits^n_{i=1}\sum\limits^m_{j=1}gcd(i,j)\)这部分我们可以快乐套路

枚举gcd的值

\(=2\sum\limits^n_{d=1}d\sum\limits^n_{i=1}\sum\limits^m_{j=1}[gcd(i,j)==d]\)

\(=2\sum\limits^n_{d=1}d\sum\limits^{\lfloor\frac{n}{d}\rfloor}_{i=1}\sum\limits^{\lfloor\frac{m}{d}\rfloor}_{j=1}[gcd(i,j)==1]\)

莫比乌斯反演下

\(=2\sum\limits^n_{d=1}d\sum\limits^{\lfloor\frac{n}{d}\rfloor}_{i=1}\sum\limits^{\lfloor\frac{m}{d}\rfloor}_{j=1}\sum\limits_{t|gcd(i,j)}\mu(t)\)

把t提到前面去

\(=2\sum\limits^n_{d=1}d\sum\limits^{\lfloor\frac{n}{d}\rfloor}_{t=1}\mu(t)\sum\limits^{\lfloor\frac{n}{dt}\rfloor}_{i=1}\sum\limits^{\lfloor\frac{m}{dt}\rfloor}_{j=1}\)

\(=2\sum\limits^n_{d=1}d\sum\limits^{\lfloor\frac{n}{d}\rfloor}_{t=1}\mu(t)\lfloor\frac{n}{dt}\rfloor\lfloor\frac{m}{dt}\rfloor\)

\(T=dt\)

\(=2\sum\limits^n_{T=1}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum\limits_{d|T}d\mu(\frac{T}{d})\)

前面的部分整除分块就能搞定那么后面的呢

我们把后面的拆出来康康\(\sum\limits_{d|T}d\mu(\frac{T}{d})=\sum\limits_{d|T}\frac{T\mu(d)}{d}=\varphi(T)\)

最后式子变成了\(=2\sum\limits^n_{T=1}\varphi(T)\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor-nm\)

这就相当好搞了

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
// freopen("k.in", "r", stdin);
// freopen("k.out", "w", stdout);
// clock_t c1 = clock();
// std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
mt19937 rnd(time(NULL));
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<char, char> PCC;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e5 + 7;
const ll MAXM = 4e5 + 7;
const int MOD = 1e9 + 7;
const double eps = 1e-7;
int vis[MAXN],tot=0;
int pri[MAXN],phi[MAXN];
ll sumphi[MAXN];
void init()
{
    phi[1]=1;
    for(int i=2; i<MAXN; i++)
    {
        if(!vis[i])
            phi[i]=i-1,pri[++tot]=i;
        for(int j=1; j<=tot&&pri[j]*i<MAXN; j++)
        {
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                phi[i*pri[j]]=phi[i]*pri[j];
                break;
            }
            else
                phi[i*pri[j]]=phi[i]*(pri[j]-1);
        }
    }
    sumphi[0]=0;
    for(int i=1;i<MAXN;i++)
        sumphi[i]=sumphi[i-1]+phi[i];
}
int main()
{
    init();
    int n,m;
    while(cin>>n>>m)
    {
        ll ans=-1LL*n*m;
        if(n>m)
            swap(n,m);
        for(int l=1,r=0;l<=n;l=r+1)
        {
            r=min(n/(n/l),m/(m/l));
            ans+=2LL*(n/l)*(m/l)*(sumphi[r]-sumphi[l-1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

posted @ 2020-10-22 16:56  GrayKido  阅读(125)  评论(0编辑  收藏  举报