题意:给出a、b、c、d、x、y,让求下列式子。
图片说明
思路:对于gcd(x,y)我们知道
gcd(x,y)=p1 ^(min(n1,n2)) * p2 ^(min(n1,n2))....pk ^(min(n1,n2))
p1、p2....pk是x和y的质因子,n1代表x中该质因子的个数,n2代表y中该质因子的个数

那么对于gcd(x,y)而言,因为这个式子是累乘的,所以gcd=1的就无需考虑。
所以我们去枚举x的质因子p,然后取看y中是不是也有该质因子p
如果y中没有,显然贡献也是1 乘起来没有影响。

假设x中质因子p的个数为n1,y中质因子p的个数为n2。
我们只需要算出来上面式子中,gcd里p的累加个数k即可,然后求p^k
这里我们考虑怎么快速求出来i从a到b,j从c到d时,gcd(p ^ ( n1 * i ),p ^ ( n2 *i ) )的累乘值。

因为这里都是p的幂次方,所以肯定是选择最小的那个了。
我们考虑遍历i,然后现在考虑怎么快速计算出当i固定时候,j从c到d的时候计算的p的个数和。
因为gcd是取最小的那个,所以对于当前i,我们计算n1 * i也就是此时(x ^ i)中有多少个p的个数
然后计算n2 * c 也就是(y ^ c)中有多少个p的个数
1、如果 n1 * i <= n2 * c ,也就是对于j取c的时候,p的个数就大于n1 * i个了,那么对于j从c到d,gcd的贡献肯定都是取最小的,也就是每次都取n1 * i,而j的遍历区间长度是d-c+1 所以此时的个数贡献就是 (d-c+1) * n1 * i
2、如果n1 * i >=n2 * d,也就是当j取最大时候j=d,前者的个数仍然比后者大,那么对于gcd而言,每次取得肯定都是j的那一部分,而这一部分就是
n2 * c + n2 * (c+1) + n2 * (c+2) ....+n2 * d=n2 * (c+(c+1)+(c+2)+....+d)=n2 * (c+d) * (d-c+1)/2

3、如果不是上述两次情况呢,那么就是说存在一个k,c≤k≤d,使得j取[c,k]时候满足第二种情况,使得j取[k,d]满足第一种情况,只需要算出来k分两段计算就好了。

这里还需要用到欧拉降幂。a ^ b%mod=a ^ (b%f(mod)) %mod 其中f(mod)指的是mod的欧拉函数值。因为题中的mod是质数,所以f(mod)=mod-1.

复杂度看似是O(sqrt(x) * (b-a+1)),但是其中最多只会进行10 * ( b-a+1)次,因为从2开始最多只要11个质数相乘,就已经大于了1e9,也就是x的范围,也就是说去进行 固定i去计算的次数最多只会进行10次。真实复杂度应该是O(max(sqrt(x),(b-a+1) * cnt ))。其中cnt是x和y中都有的质因子的种类数

实测跑的还挺快的
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const ll mod2=mod-1;
ll a,b,c,d,x,y;
ll qpow(ll a,ll b){
    ll ans=1;
    a%=mod;
    while(b){
        if(b&1)  ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
ll check(ll n1,ll n2){
    ll sum=0;
    for(ll i=a;i<=b;i++){
        ll cnt=n1*i;
        if(cnt<n2*c){
            sum+=cnt%mod2*(d-c+1)%mod2;
        }
        else if(cnt>n2*d){
            sum+=(d-c+1)*(c+d)/2%mod2*n2%mod2;
        }
        else{
            ll k=cnt/n2;
            sum+=(k-c+1)*(k+c)/2%mod2*n2%mod2;
            sum%=mod2;
            sum+=cnt%mod2*(d-k)%mod2;
        }
        sum%=mod2;
    }
    return sum%mod2;
}
int main(){
    cin>>a>>b>>c>>d>>x>>y;
    ll ans=1;
    for(ll i=2;i*i<=x;i++){
        if(x%i==0){
            int cx=0,cy=0;
            while(x%i==0) x/=i,cx++;
            while(y%i==0) y/=i,cy++;
            if(cy) ans*=qpow(i,check(cx,cy)),ans%=mod;
        }
    }
    if(x!=1){
        int cy=0;
        while(y%x==0) y/=x,cy++;
        if(cy) ans*=qpow(x,check(1,cy)),ans%=mod;

    }
    cout<<ans<<endl;
    return 0;
}