# E Groundhog Chasing Death（2020牛客暑期多校训练营（第九场））（思维+费马小定理+质因子分解）

64bit IO Format: %lld

## 题目描述

As we all know,“Groundhog chasing death” means “GCD”,while “GCD” stands for “greatest common divisor”.

So you need to calculate ∏ i = a b ∏ j = c d gcd ⁡ ( x i , y j ) \displaystyle\prod_{i=a}^b\prod_{j=c}^d\gcd(x^i,y^j) modulo 998244353 {998244353} .

## 输入描述:

One line which contains six intergers a , b , c , d , x , y {a,b,c,d,x,y} .

## 输出描述:

One line which contains
∏ i = a b ∏ j = c d gcd ⁡ ( x i , y j ) \displaystyle\prod_{i=a}^b\prod_{j=c}^d\gcd(x^i,y^j) modulo 998244353 {998244353} .

## 示例1

### 输入

1 2 1 2 8 4


### 输出

2048


## 示例2

### 输入

1 2 3 4 120 180


### 输出

235140177


## 备注:

0 ⩽ a , b , c , d ⩽ 3 × 1 0 6 , 0 < x , y ⩽ 1 0 9 , a ⩽ b , c ⩽ d 0\leqslant{a,b,c,d\leqslant 3\times10^6,0<x,y\leqslant10^9},a\leqslant b,c\leqslant d .

## 题解

x x y y 中每个素因子的个数分开考虑，因为题目要求的是求所有gcd的乘积，所以我们把用于构建gcd的素因子的个数直接加起来即可。

## 代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define scl(x) scanf("%lld", &x)
using namespace std;
typedef long long LL;
const int mod = 998244353;
int debug = 0;

LL a, b, c, d, x, y;
vector<LL> gcdd, gnumx, gnumy, mi;  //gcdd保存x和y的公共素因子，gnumx保存x中每个公共素因子的个数，gnumy保存y中每个公共素因子的个数，mi保存最终答案中每个公共素因子的个数。

inline void init() {
gcdd.clear();
gnumx.clear();
gnumy.clear();
mi.clear();
}

struct Prime {
vector<int> arr;
int vis[100006];
void doit(int maxnum) {
for(int i = 2; i <= maxnum; ++i) {
if(!vis[i]) arr.push_back(i);
for(int j = 0; j < arr.size() && arr[j] * i <= maxnum; ++j) {
vis[arr[j] * i] = 1;
if(i % arr[j] == 0) break;
}
}
}
}P;

inline LL quickPow(LL x, LL n) {
LL ans = 1;
while(n) {
if(n & 1) ans *= x, ans %= mod;
x *= x, x %= mod;
n >>= 1;
}
return ans;
}

inline void sol() {
init();
LL g = __gcd(x, y);
for(int i = 0; P.arr[i] * P.arr[i] <= g; ++i) { //把x和y的最大公约数分解，把素因子存起来
if(g % P.arr[i] == 0) {
gcdd.push_back(P.arr[i]);
while(g % P.arr[i] == 0) g /= P.arr[i];
}
}
if(g > 1) gcdd.push_back(g);
mi.resize(gcdd.size());
fill(mi.begin(), mi.end(), 0);
LL tx = x, ty = y;
for(auto &i : gcdd) {       //求出每个素因子在x和y中出现的次数
gnumx.push_back(0);
while(tx % i == 0) {
++gnumx.back();
tx /= i;
}
gnumy.push_back(0);
while(ty % i == 0) {
++gnumy.back();
ty /= i;
}
}
if(debug) {
_for(i, gcdd.size()) {
printf("%d: x %d, y %d\n", gcdd[i], gnumx[i], gnumy[i]);
}
}
LL ans = 1;
_rep(i, a, b) {             //枚举每一个i，计算j的贡献
_for(x, gcdd.size()) {
LL numx = 0;
LL num = gnumx[x] * i;
LL m = num / gnumy[x];
if(m >= c) {        //gcd的值主要被y的素因子个数所限制，等差数列求和
LL r = min(m, d);
numx += gnumy[x] * (r + c) * (r - c + 1) / 2;
}
if(d > m) {         //gcd的值主要被x的素因子个数所限制，此时j的贡献是一段恒定的值
LL l = max(m + 1, c);
numx += num * (d - l + 1);
}
mi[x] += numx;
mi[x] %= (mod - 1);//费马小定理
}
}
_for(i, gcdd.size()) {
ans = ans * quickPow(gcdd[i], mi[i]) % mod;
}
printf("%lld\n", ans);
}

int main() {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
debug = 1;
#endif
time_t beg, end;
if(debug) beg = clock();

P.doit(100000);
while(~scl(a)) {
scl(b), scl(c), scl(d), scl(x), scl(y);
sol();
}

if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
return 0;
}

/*
in:
0 3000000 0 3000000
223092870
223092870

out:
824590783

*/

05-19

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客