【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
*/
posted @ 2020-08-10 09:59  Valk3  阅读(88)  评论(0编辑  收藏  举报