【2020 牛客多校】第 9 場 E. Groundhog Chasing Death 列舉
阿新 • • 發佈:2020-08-10
題意
給出 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\)
那麼根據 gcd ,當 \(j\leq mid\) 的時候,p 對答案的貢獻的冪次為 \(y^j\) 中 \(p\) 的出現次數,即 \(yp\times j\),當 \(j\geq mid\) 時,\(p\) 對答案的貢獻冪次為 \(x^i\) 的質因子中 \(p\) 的出現次數,即\(xp\times i\)。
-
\(j \leq mid\)
if mid >= c: mid = min(mid,d) num = (c + mid) * (num - c + 1) / 2 * yp
-
\(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 */