2018 Multi-University Training Contest 7 6390 GuGuFishtion【莫比烏斯反演】
阿新 • • 發佈:2018-12-24
昨天一下午,今天一上午,我已經快被這個題噁心死了。
TLE,TLE永遠都是TLE。不得不說,我覺得卡我卡的沒什麼道理,非常的不爽!
卡內迴圈列舉變數型別我是真的不懂,發現知識盲區+1.
可是就算是再不爽也要含淚挖坑。
題意求:
打表規律發現:
所以就可以通過莫比烏斯反演來計算
最後通過列舉並乘上和[的逆元]即可
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$!