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 2 1 2 8 4
2048
1 2 3 4 120 180
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)(实际复杂度远比这小)
值得注意的地方有两个:
1.要使用欧拉降幂加速
2.使用欧拉降幂时注意模数是 p − 1 p-1 p−1不是 p p p(具体的请看代码)
#include
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