1. 程式人生 > 實用技巧 >【2020 牛客多校】第 9 場 E. Groundhog Chasing Death 列舉

【2020 牛客多校】第 9 場 E. Groundhog Chasing Death 列舉

Groundhog Chasing Death

題意

給出 a, b, c, d, x, y,讓求出 \(\prod_{i=a}^{b}\prod_{i=c}^{d}gcd(x^i,y^j)\%mod\)

思路

先求出 \(x\), \(y\) 的 gcd,進行質因子分解,然後第一層 for 迴圈列舉質因子,第二層 for 迴圈列舉 \(i\)

對於質因子 \(p\)\(i\),假設 \(p\)\(x\) 中出現了 \(xp\) 次,在 \(y\) 中出現了 \(yp\) 次,我們可以求出一個分界線 \(mid\)

使得當 \(j\leq mid\) 時,\(x^i\)\(p\)

的出現次數大於等於 \(y^{j}\)\(p\) 的出現次數,即 \(xp \times i \geq yp \times j\) ;當 \(j\geq mid\) 時, \(x^i\)\(p\) 的出現次數小於等於\(y^{j}\)\(p\) 的出現次數;

那麼根據 gcd ,當 \(j\leq mid\) 的時候,p 對答案的貢獻的冪次為 \(y^j\)\(p\) 的出現次數,即 \(yp\times j\),當 \(j\geq mid\) 時,\(p\) 對答案的貢獻冪次為 \(x^i\) 的質因子中 \(p\) 的出現次數,即\(xp\times i\)

  1. \(j \leq mid\)

    時貢獻的冪次為

    if mid >= c:
    	mid = min(mid,d)
        num = (c + mid) * (num - c + 1) / 2 * yp
    
  2. \(j \geq mid\) 時貢獻的冪次為

    if mid <= d:
    	mid = max(mid, c - 1)
        num = (d - mid ) * xp
    

注意:對於每個 i 求出來 p 的貢獻冪次之後,不要直接使用快速冪計算,把所有 i 中 p 的貢獻冪次累加起來,最後進行快速冪,否則會超時,冪次和使用__int128

程式碼

#include <bits/stdc++.h>
#define fuck system("pause")
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const double eps = 1e-6;
const ll inf = 0x3f3f3f3f;
const ll N = 2e5 + 10; 

ll tot, vec[N];
void find_fat(ll val)
{
    tot = 0;
    for (ll i = 2; i * i <= val; i++) {
        if (val % i == 0) {
            vec[++tot] = i;
        }
        while (val % i == 0)
            val /= i;
    }
    if (val > 1)
        vec[++tot] = val;
}

ll qpow(ll a, __int128 b)
{
    ll ans = 1;
    while (b) {
        if (b & 1) {
            ans = (ans * a) % mod;
        }
        b >>= 1;
        a = a * a % mod;
    }
    return ans % mod;
}

int main()
{
    ll a, b, x, y, c, d;
    scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &x, &y);
    ll gcd = __gcd(x, y);
    find_fat(gcd);
    ll ans = 1, xp = 0, yp = 0, p, tmp;
    for (ll j = 1; j <= tot; j++) {//列舉質因子
        p = vec[j], tmp = x;
        xp = yp = 0;
        while (tmp % p == 0) {
            xp++;
            tmp /= p;
        }
        tmp = y;
        while (tmp % p == 0) {
            yp++;
            tmp /= p;
        }
        __int128 sum = 0;
        for (ll i = a; i <= b; i++) {
            ll r = yp, l = xp * i;
            ll num = l / r;
            if (num >= c) {
                ll maxn = min(num, d);
                sum+=(c + maxn) * (maxn - c + 1) / 2 * r;
            }
            if (num <= d) {
                ll minn = max(num, c - 1);
                sum += (d - minn) * l;
            }
        }
        ans = (ans * qpow(p, sum)) % mod;
    }
    printf("%lld\n", ans);
    return 0;
}
/*
1 3000000 1 3000000 500000000 500000000
*/