多校1005GuGuFishtion &6390 GuGuFishtion

1005GuGuFishtion

数论题,预处理+容斥
这里写图片描述

后面的部分可以用容斥做,令

F[k]=i=1i=Mj=1j=N[gcd(i,j)=k] F [ k ] = ∑ i = 1 i = M ∑ j = 1 j = N [ g c d ( i , j ) = k ]

F[k]=(M/k)(N/k)F[2k]F[3k].... F [ k ] = ( M / k ) ∗ ( N / k ) − F [ 2 ∗ k ] − F [ 3 ∗ k ] − . . . .

倒着求F[K] 即可,复杂度O(nlog(n))
for(int i = N; i; --i){
        F[i] = 1ll*(N/i)*(M/i);
        // if(i == 1) cout<<F[i]<<endl;
        for(int j = i+i;j <= N; j += i)
             F[i] -= F[j];
    }

#include <bits/stdc++.h>
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define pb push_back
#define  FI first
#define  SE second
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl;
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
// const LL     mod = 1e9 + 7;
// LL qpow(LL a,LL b,LL mod){LL s=1;while(b>0){if(b&1)s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
// typedef pair<int,int> p;

const int maxn = 1e6+1000;
LL F[maxn],phi[maxn], inv[maxn];
LL  N,M,P;
void init(int n){
    for(int i = 1;i <= n; ++i) phi[i] = i;
    for(int i = 2;i <= n; ++i){
        if(i == phi[i]){
           for(int j = i; j <= n; j += i) phi[j] = phi[j]/i*(i-1);
        }
    }
}
void init2(void){
    inv[1] = 1;
    for(int i = 2;i <= N; ++i)
        inv[i] = (P - P/i*inv[P%i]%P)%P;
    for(int i = N; i; --i){
        F[i] = 1ll*(N/i)*(M/i);
        // if(i == 1) cout<<F[i]<<endl;
        for(int j = i+i;j <= N; j += i)
             F[i] -= F[j];
    }
    //cout<<F[1]<<endl;
    // DEBUG
   /* for(int i = 1;i <= N; ++i)
       cout<<F[i]<<" ";
    cout<<endl;
    int FF[100];
    me(FF);
    for(int i = 1;i <= N; ++i)
        for(int j = 1;j <= M; ++j) 
             FF[gcd(i,j)]++;
     for(int i = 1;i <= N; ++i)
       cout<<FF[i]<<" ";
    cout<<endl;*/
}
LL solve(){
    init2();
    LL ans = 0;
    for(LL i = 1;i <= N; ++i){
          ans += (LL)i*inv[phi[i]]%P*(F[i]%P)%P;
          assert(ans >= 0);
          ans %= P;
    }
    // LL ans2 = 0;
/*  DEBUG
    for(int i = 1;i <= N; ++i){
        for(int j = 1;j <= M; ++j)
            ans2 += gcd(i,j)*inv[phi[gcd(i,j)]]%P;
    }
    ans2 %= P;
    if(ans2 != ans) {
       cout<<"ERROR"<<" "<<N<<" "<<M<<" "<<P<<endl;
       cout<<ans<<" "<<ans2<<endl;
    }*/
    return ans%P;
}
// #define Debug
int main(void)
{
    #ifdef Debug
    freopen("input.txt","r",stdin);
    freopen("output1.txt","w+",stdout);
    #endif
    init(maxn-1);
    int T;
    cin>>T;
    while(T--){
        cin>>N>>M>>P;
        if( N < M) swap(N,M);
        cout<<solve()<<endl;
    }


   return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值