原题题面
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
)
\prod_{i=a}^b\prod_{j=c}^d\gcd(x^i,y^j)
∏i=ab∏j=cdgcd(xi,yj) modulo
998244353
998244353
998244353
输入格式
One line which contains six intergers a , b , c , d , x , y a,b,c,d,x,y a,b,c,d,x,y.
0 ≤ a , b , c , d ≤ 3 e 6 , a ≤ b , c ≤ d , 0 ≤ x , y ≤ 1 e 9 0\leq a,b,c,d\leq 3e6,a\leq b,c\leq d,0\leq x,y \leq 1e9 0≤a,b,c,d≤3e6,a≤b,c≤d,0≤x,y≤1e9
输出格式
One line which contains ∏ i = a b ∏ j = c d gcd ( x i , y j ) \prod_{i=a}^b\prod_{j=c}^d\gcd(x^i,y^j) ∏i=ab∏j=cdgcd(xi,yj) modulo 998244353 998244353 998244353
输入样例1
1 2 1 2 8 4
输出样例1
2048
输入样例2
1 2 3 4 120 180
输出样例2
235140177
题面分析
第一眼以为是莫反就屁颠屁颠地化式子去了,果然画不出来
首先我们给出gcd的另一种定义,
对于
a
=
∏
i
=
1
m
p
i
x
i
,
b
=
∏
i
=
1
n
p
i
y
i
a=\prod_{i=1}^{m}p_{i}^{x_i},b=\prod_{i=1}^{n}p_{i}^{y_i}
a=∏i=1mpixi,b=∏i=1npiyi
g
c
d
(
a
,
b
)
=
∏
i
=
1
m
i
n
(
m
,
n
)
p
i
m
i
n
(
x
i
,
y
i
)
gcd(a,b)=\prod_{i=1}^{min(m,n)}p_{i}^{min(x_i,y_i)}
gcd(a,b)=∏i=1min(m,n)pimin(xi,yi)
证明略,稍加理解即可。
那我们可以考虑去计算每个质因子
p
i
p_i
pi对答案的贡献。
把原式的
x
,
y
x,y
x,y质因子分解后,对于某一个质因子
p
p
p,设
x
x
x对应的次数为
k
1
k_1
k1,
y
y
y对应的次数为
k
2
k_2
k2
那么
p
i
p_i
pi的贡献就是
p
i
∑
i
=
1
b
∑
j
=
c
d
m
i
n
(
k
1
i
,
k
2
j
)
p_i^{\sum_{i=1}^{b}\sum_{j=c}^{d}min(k_1i,k_2j)}
pi∑i=1b∑j=cdmin(k1i,k2j)
对于
∑
i
=
1
b
∑
j
=
c
d
m
i
n
(
k
1
i
,
k
2
j
)
\sum_{i=1}^{b}\sum_{j=c}^{d}min(k_1i,k_2j)
∑i=1b∑j=cdmin(k1i,k2j)
根据
m
i
n
min
min的取值不同,我们分成两种情况。
①
k
1
i
≤
k
2
j
k_1i\leq k_2j
k1i≤k2j
此时可以得到
j
≥
k
1
k
2
i
j\geq\frac{k_1}{k_2}i
j≥k2k1i,所以这部分求和的结果是
∑
i
=
a
b
∑
j
=
m
a
x
(
c
,
⌈
k
1
k
2
i
⌉
)
d
k
1
i
\sum_{i=a}^{b}\sum_{j=max(c,\lceil\frac{k_1}{k2}i\rceil)}^{d}k_1i
∑i=ab∑j=max(c,⌈k2k1i⌉)dk1i
化简得
k
1
∑
i
=
a
b
i
∗
[
d
−
m
a
x
(
c
,
⌈
k
1
k
2
i
⌉
)
+
1
]
k_1\sum_{i=a}^{b}i*[d-max(c,\lceil\frac{k_1}{k_2}i\rceil)+1]
k1∑i=abi∗[d−max(c,⌈k2k1i⌉)+1]
②
k
1
i
>
k
2
j
k_1i>k_2j
k1i>k2j
此时可以得到
i
>
k
2
k
1
j
i>\frac{k_2}{k_1}j
i>k1k2j,所以这部分求和的结果是
∑
j
=
c
d
∑
i
=
m
a
x
(
a
,
⌈
k
1
k
2
j
⌉
)
b
k
2
j
\sum_{j=c}^{d}\sum_{i=max(a,\lceil\frac{k_1}{k2}j\rceil)}^{b}k_2j
∑j=cd∑i=max(a,⌈k2k1j⌉)bk2j
同理得到
k
2
∑
j
=
c
d
j
∗
[
b
−
m
a
x
(
a
,
⌊
k
2
k
1
j
⌋
+
1
)
+
1
]
k_2\sum_{j=c}^{d}j*[b-max(a,\lfloor\frac{k_2}{k_1}j\rfloor+1)+1]
k2∑j=cdj∗[b−max(a,⌊k1k2j⌋+1)+1]
所以
∑
i
=
1
b
∑
j
=
c
d
m
i
n
(
k
1
i
,
k
2
j
)
\sum_{i=1}^{b}\sum_{j=c}^{d}min(k_1i,k_2j)
∑i=1b∑j=cdmin(k1i,k2j)
=
k
1
∑
i
=
a
b
i
∗
[
d
−
m
a
x
(
c
,
⌈
k
1
k
2
i
⌉
)
+
1
]
+
k
2
∑
j
=
c
d
j
∗
[
b
−
m
a
x
(
a
,
⌊
k
2
k
1
j
⌋
+
1
)
+
1
]
=k_1\sum_{i=a}^{b}i*[d-max(c,\lceil\frac{k_1}{k_2}i\rceil)+1]+k_2\sum_{j=c}^{d}j*[b-max(a,\lfloor\frac{k_2}{k_1}j\rfloor+1)+1]
=k1∑i=abi∗[d−max(c,⌈k2k1i⌉)+1]+k2∑j=cdj∗[b−max(a,⌊k1k2j⌋+1)+1]
因为质因子的个数很小,前9个质数相乘就已经超出
1
e
9
1e9
1e9了,故枚举质因子复杂度为
O
(
9
)
O(9)
O(9)
暴力计算贡献的复杂度是
O
(
3
e
6
)
O(3e6)
O(3e6)
质因子分解的复杂度最大是
O
(
32
)
O(32)
O(32)(即
x
=
2
32
x=2^{32}
x=232的时候)
因此总复杂度为
O
(
9
×
3
e
6
×
32
)
O(9\times3e6\times32)
O(9×3e6×32)(实际复杂度远比这小)
AC代码(1175ms)
值得注意的地方有两个:
1.要使用欧拉降幂加速
2.使用欧拉降幂时注意模数是
p
−
1
p-1
p−1不是
p
p
p(具体的请看代码)
#include<bits/stdc++.h>
using namespace std;
const long long MAXN=2e5;
const long long mod=998244353;
int prime[MAXN];//素数数组
bool is_prime[MAXN+10];//is_pri[i]表示i是素数
int factorX[MAXN+10];
int sumX=0;
int sumY=0;
int factorY[MAXN+10];
long long a, b, c, d, x, y;
int sumPrime;
//返回n以内素数的个数
inline long long quick_pow(long long a, long long b)//快速幂
{
long long ans=1, base=a;
while(b!=0)
{
if (b&1)
ans=(long long) ans*base%mod;
base=(long long) base*base%mod;
b>>=1;
}
return ans;
}
int sieve(int n)
{
int p=0;//素数个数计数器
for(int i=0; i<=n; i++)
is_prime[i]=true;
is_prime[0]=is_prime[1]=false;//首先标记0和1不是素数
is_prime[2]=true;//标记2是素数
for(int i=2; i<=sqrt(n); i++)
{
if (is_prime[i]) //如果i是素数
{
for(int j=i*i; j<=n; j+=i)//所有i的倍数都不是素数
is_prime[j]=false;
}
}
for(int i=1; i<=n; i++)
if (is_prime[i])
prime[++p]=i;
return p;
}
void init()//质因子分解
{
for(int i=1; i<=sumPrime && x!=1; i++)
{
if (x%prime[i]==0)
{
sumX=i;
while(x!=1 && x%prime[i]==0)
{
x/=prime[i];
factorX[i]++;
}
}
}
if (x!=1)
{
sumPrime++;
prime[sumPrime]=x;
factorX[sumPrime]++;
}
for(int i=1; i<=sumPrime && y!=1; i++)
{
if (y%prime[i]==0)
{
sumY=i;
while(y!=1 && y%prime[i]==0)
{
y/=prime[i];
factorY[i]++;
}
}
}
if (y!=1)
{
sumPrime++;
prime[sumPrime]=y;
factorY[sumPrime]++;
}
}
void solve()
{
sumPrime=sieve((int) 2e5);
scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &x, &y);
init();
long long ans=1;
for(int z=1; z<=min(sumX, sumY); z++)
{
if (factorX[z] && factorY[z])
{
long long powP1=0, powP2=0;
for(long long i=a; i<=b; i++)
{
long long j;
if(factorX[z]*i%factorY[z]==0)
{
j=(long long)max(factorX[z]*i/factorY[z],c);
}
else
{
j=(long long)max(factorX[z]*i/factorY[z]+1,c);
}
if (j<=d && j>=0)
powP1=(powP1+(long long) i*((d-j+1+(mod-1))%(mod-1))%(mod-1))%(mod-1);
}
powP1=(long long) powP1*factorX[z]%(mod-1);
for(long long i=c; i<=d; i++)
{
long long j;
j=(long long) max(factorY[z]*i/factorX[z]+1, a);
if (j<=b && j>=0)
powP2=(powP2+(long long) i*((b-j+1+(mod-1))%(mod-1))%(mod-1))%(mod-1);
}
powP2=(long long) powP2*factorY[z]%(mod-1);
ans=(long long) (ans*quick_pow(prime[z], (powP1+powP2)%(mod-1)))%mod;
}
}
printf("%lld\n", ans);
}
int main()
{
// ios_base::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long long test_index_for_debug=1;
char acm_local_for_debug;
while(cin>>acm_local_for_debug)
{
cin.putback(acm_local_for_debug);
if (test_index_for_debug>100)
{
throw runtime_error("Check the stdin!!!");
}
auto start_clock_for_debug=clock();
solve();
auto end_clock_for_debug=clock();
cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;
cerr<<"Test "<<test_index_for_debug++<<" Run Time: "
<<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;
cout<<"--------------------------------------------------"<<endl;
}
#else
solve();
#endif
return 0;
}
后记
赛中傻逼了,欧拉降幂模数一直错,白白WA了3发…
DrGilbert 2020.8.9