1. 程式人生 > >2018 Multi-University Training Contest 7 6390 GuGuFishtion【莫比烏斯反演】

2018 Multi-University Training Contest 7 6390 GuGuFishtion【莫比烏斯反演】

昨天一下午,今天一上午,我已經快被這個題噁心死了。
TLE,TLE永遠都是TLE。不得不說,我覺得卡我卡的沒什麼道理,非常的不爽!

卡內迴圈列舉變數型別我是真的不懂,發現知識盲區+1.

可是就算是再不爽也要含淚挖坑。

題意求:

(a=1mb=1nϕ(ab)ϕ(a)ϕ(b))mod(p)

打表規律發現:

ϕ(ab)ϕ(a)ϕ(b)=gcd(a,b)ϕ(gcd(a,b))

所以就可以通過莫比烏斯反演來計算

a=1nb=1m[k=gcd(a,b)]

最後通過列舉k並乘上k和[ϕ(k)的逆元]即可

AC程式碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
ll phi[maxn];
ll mu[maxn];
ll inv[maxn];
ll a[maxn];
ll cnt;ll p;ll T;int n,m;
void get_inv(ll n){
    inv[1]=1;
    for(ll i=2;i<=n;i++){
        inv[i]=(ll)(p-p/i)*inv[p%i]%p;
    }
    for
(ll i=1;i<=n;i++){ a[i]=(ll)i*inv[phi[i]]%p; } } void get_phi(){ for(ll i=1;i<maxn;i++){ phi[i]=i; } for(ll i=2;i<maxn;i++){ if(phi[i]==i){ for(ll j=i;j<maxn;j+=i) phi[j]-=phi[j]/i; } } } void get_mu() { mu[1
] = 1; for(int i=1;i<maxn;i++){ for(int j=2*i;j<maxn;j+=i){ mu[j]-=mu[i]; } } } int main() { get_phi(); get_mu(); scanf("%lld", &T); while (T--) { scanf("%d%d%lld", &n, &m, &p); if (n > m) swap(n, m); ll res=min(n,m); get_inv(res); ll ans=0; ll tmp=0; for(ll d=1;d<=res;d++){ tmp=0; //for (ll l = 1, r; l <= res; l = r + 1) { // r = min(n / (n / l), m / (m / l)); // tmp += 1ll*(n / (l*d))*(m / (l* d))*(sum[r] - sum[l - 1])%p; // } int x=n/d,y=m/d; ll tmp=0; for(int j=1;j<=min(x,y);j++){ tmp+=(ll)mu[j]*(x/j)*(y/j); tmp%=p; } ans+=tmp*a[d]; ans%=p; } printf("%lld\n", ans); } return 0; }

神煩啊QAQ$!