Gym - 102460M DivModulo

题意:

定义 n   d m o d   d = m × d x   d m o d   d = m   m o d   d n~dmod~d = m × d^x~dmod~d = m~mod~d n dmod d=m×dx dmod d=m mod d,其中 n = m × d x n = m × d^x n=m×dx d d d 不是 m m m 的因子。先给定 M , N , D M, N, D M,N,D,求 C ( M , N )   d m o d   D C(M, N)~dmod~D C(M,N) dmod D ( N ≤ M ≤ 4 × 1 0 18 , 2 ≤ D ≤ 1.6 × 1 0 7 ) (N \leq M \leq 4 × 10^{18}, 2 \leq D \leq 1.6 × 10^7) (NM4×1018,2D1.6×107)

链接:

https://vjudge.net/problem/Gym-102460M

解题思路:

由于习惯,将题目里的 N M NM NM 对调一下,即求 C ( N , M )   d m o d   D C(N, M)~dmod~D C(N,M) dmod D。记 N / D N/D N/D N N N 去掉所有 D D D 因子后所得数,当 D D D 为质数时,
C ( N , M ) = N ! M ! ∗ ( N − M ) ! = N ! / D M ! / D ∗ ( N − M ) ! / D ∗ D K C(N, M) = \cfrac{N!}{M!*(N-M)!}=\cfrac{N!/D}{M!/D * (N-M)!/D} * D^K C(N,M)=M!(NM)!N!=M!/D(NM)!/DN!/DDK
很显然,答案是前面那部分,由于分母不含 D D D 因子,分母与 D D D 互质,逆元存在,
a n s = N ! / D ∗ i n v ( M ! / D ) ∗ i n v ( N − M ) ! / D )   m o d   D ans = N!/D * inv(M!/D) * inv(N-M)!/D)~mod~D ans=N!/Dinv(M!/D)inv(NM)!/D) mod D

n ! ≡ ∏ d ∣ i i ∗ ∏ d ∤ i i ≡ {   d ⌊ n d ⌋ ∗ ⌊ n d ⌋ !   } ∗ {   [   ∏ d ∤ i i ∈ [ 1 , p ] i   ] ⌊ n p ⌋ ∗ ∏ d ∤ i i ∈ [ 1 , n % p ] i   } ( m o d   p ) n! \equiv \prod\limits_{d\mid i}i * \prod\limits_{d \nmid i}i \equiv \{~d^{\lfloor\frac{n}{d}\rfloor} * \lfloor\cfrac{n}{d}\rfloor!~\} * \{~[~{\prod\limits_{d\nmid i}^{i\in [1,p]} i~]}^{\lfloor\frac{n}{p}\rfloor} * \prod\limits_{d \nmid i}^{i\in[1,n\%p]}i~\} \quad (mod~p) n!diidii{ ddndn! }{ [ dii[1,p]i ]pndii[1,n%p]i }(mod p)

f ( n ) = n ! / d   m o d   p ,   g ( n ) = ∏ d ∤ i i ∈ [ 1 , n ] i   m o d   p f(n) = n!/d~mod~p,~g(n) = \prod\limits_{d \nmid i}^{i \in [1,n]} i~mod~p f(n)=n!/d mod p, g(n)=dii[1,n]i mod p

f ( n ) = f ( n / d ) ∗ g ( p ) ⌊ n p ⌋ ∗ g ( n % p )   m o d   p f(n)=f(n/d) * g(p)^{\lfloor\frac{n}{p}\rfloor} * g(n \% p)~mod~p f(n)=f(n/d)g(p)png(n%p) mod p
O ( p ) O(p) O(p) 预处理出 g ( n ) g(n) g(n),则可以快速求得 f ( n ) f(n) f(n)
 
D D D 不是质数时,分母与 D D D 不一定互质,将 D D D 唯一分解:
D = D 1 ∗ D 2 ∗ . . . ∗ D s = p 1 α 1 ∗ p 2 α 2 ∗ . . . ∗ p s α s D = D_1 * D_2 * ... * D_s = p_1^{\alpha_1} * p_2^{\alpha_2} * ... * p_s^{\alpha_s} D=D1D2...Ds=p1α1p2α2...psαs
依然可以求出
C ( N , M ) = N ! M ! ∗ ( N − M ) ! = N ! / p i M ! / p i ∗ ( N − M ) ! / p i ∗ p i k i C(N, M) = \cfrac{N!}{M!*(N-M)!}=\cfrac{N!/p_i}{M!/p_i * (N-M)!/p_i} * p_i^{k_i} C(N,M)=M!(NM)!N!=M!/pi(NM)!/piN!/pipiki
进一步可以得到 D K D^K DK K = min ⁡ i = 1 s k i α i K = \min\limits_{i=1}^{s}\cfrac{k_i}{\alpha_i} K=i=1minsαiki
C ( N , M ) = A C(N, M) = A C(N,M)=A,有
a n s ≡ A / D ≡ A D K ≡ A / p i ∗ p i k i D K ≡ A / p i ∗ p i k i − K ∗ α i ( D D i ) K ( m o d   D i ) ans \equiv A / D \equiv \cfrac{A}{D^K} \equiv \cfrac{A / p_i * p_i^{k_i}}{D^K} \equiv \cfrac{A/p_i * p_i^{k_i - K * \alpha_i}}{(\frac{D}{D_i})^K} \quad (mod~D_i) ansA/DDKADKA/pipiki(DiD)KA/pipikiKαi(mod Di)
此时分母与模数互质,可以求出 a n s % D i ans \% D_i ans%Di 的结果,再用 c r t crt crt 求解即可。

参考代码:
#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

ll tp[16000005];
ll m[maxn], a[maxn], pi[maxn], num[maxn], ki[maxn];
ll n, N, M, D, K;

ll qpow(ll a, ll b, ll p){

    ll ret = 1;
    while(b){

        if(b & 1) ret = ret * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return ret;
}

void exgcd(ll a, ll b, ll &x, ll &y, ll &d){

    if(!b) d = a, x = 1, y = 0;
    else exgcd(b, a % b, y, x, d), y -= a / b * x;
}

ll inv(ll a, ll p){

    ll x, y, d;
    exgcd(a, p, x, y, d);
    x = (x % p + p) % p;
    return x;
}

ll crt(){

    ll M = 1, ret = 0, x, y, d;
    for(int i = 1; i <= n; ++i) M *= m[i];
    for(int i = 1; i <= n; ++i){

        exgcd(M / m[i], m[i], x, y, d);
        x = (x % m[i] + m[i]) % m[i];
        ret = (ret + M / m[i] * x % M * a[i] % M) % M;
    }
    return ret;
}

ll cal(ll x, ll p){

    ll ret = 0;
    while(x){

        ret += x / p;
        x /= p;
    }
    return ret;
}

ll cal_fac(ll p){

    return cal(N, p) - cal(M, p) - cal(N - M, p);
}

ll dfs(ll n, ll pi, ll p){

    if(!n) return 1;
    ll ret = qpow(tp[p], n / p, p) * tp[n % p] % p;
    return ret * dfs(n / pi, pi, p) % p;
}

ll cal_rem(ll pi, ll p){

    tp[0] = 1;
    for(ll i = 1; i <= p; ++i){

        tp[i] = tp[i - 1];
        if(i % pi) tp[i] = tp[i] * i % p;
    }
    return dfs(N, pi, p) * inv(dfs(M, pi, p), p) % p * inv(dfs(N - M, pi, p), p) % p;
}

void init(){

    ll x = D;
    for(ll i = 2; i * i <= x; ++i){

        if(x % i) continue;
        num[++n] = 0, pi[n] = i, m[n] = 1;
        while(x % i == 0) ++num[n], x /= i, m[n] *= i;
    }
    if(x > 1) num[++n] = 1, pi[n] = m[n] = x;
}

int main(){
 
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> N >> M >> D;
    init();
    ki[1] = cal_fac(pi[1]), K = ki[1] / num[1];
    for(int i = 2; i <= n; ++i){
        
        ki[i] = cal_fac(pi[i]);
        K = min(K, ki[i] / num[i]);
    }
    for(int i = 1; i <= n; ++i){

        a[i] = cal_rem(pi[i], m[i]) * qpow(pi[i], ki[i] - K * num[i], m[i]) % m[i] * qpow(inv(D / m[i], m[i]), K, m[i]) % m[i];
    }
    ll ret = crt();
    cout << ret << endl;
    return 0;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值