题意:给出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; }