P10084 [GDKOI2024 提高组] 计算 题解

先考虑怎么求 \(F(x,a,b)\),易得 \(\gcd(x^a-1,x^b-1)=x^{\gcd(a,b)}-1\)

所以 \(L=m^{\gcd(a,b)}+1,R=m^{\gcd(c,d)}\),然后发现 \([L,R]\) 中的数模 \(m\) 后每种余数出现次数相同,下面记其为 \(n=\frac{R-L}{m}\)

考虑用生成函数做,易得答案为:

\[\sum_{i=0}^{\infty}[m\mid i][x^i]\prod_{j=0}^{m-1}(x^j+1)^n \]

套一下单位根反演的式子 \(\sum_{k=0}^{\infty}[n\mid k]f_k=\frac{1}{m}\sum_{i=0}^{m-1}f(\omega_m^i)\) 得:

\[\frac{1}{m}\sum_{i=0}^{m-1}\prod_{j=0}^{m-1}(\omega_m^{ij}+1)^n \]

注意到 \(\omega_m^m=1\)。设 \(d=\gcd(m,i)\),那么 \(ij \operatorname{mod} m\) 对于所有 \(j=0,1,\dots,m-1\) 恰好取遍了 \(\{0,d,2d,\dots,m-d\}\) 中的每个数各 \(d\) 次,于是枚举 \(d\),式子转化为:

\[\begin{aligned} &\frac{1}{m}\sum_{k|m}\varphi(\frac{m}{k})\prod_{j=0}^{m/k-1}(\omega_m^{kj}+1)^{nk}\\ =&\frac{1}{m}\sum_{k|m}\varphi(\frac{m}{k})\left(\prod_{j=0}^{m/k-1}(\omega_{m/k}^{j}+1)\right)^{nk} \end{aligned} \]

考虑右边这个括号里的东西怎么求,由因式分解知识可得 \(x^k-1=\prod_{i=0}^{k-1}(x-\omega_k^i)\),带入 \(x=-1\) 就出来了,于是式子转化为:

\[\frac{1}{m}\sum_{k|m}\varphi(\frac{m}{k})2^{nk}[2\nmid \frac{m}{k}] \]

然后直接 \(\mathcal O(\sqrt m)\) 枚举 \(m\) 的每个因子做就好了,可以通过此题。

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define mxn 10000003
#define md 998244353
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
ll power(ll x,int y){
	ll ans=1;
	for(;y;y>>=1){
		if(y&1)ans=ans*x%md;
		x=x*x%md;
	}
	return ans;
}
ll power1(ll x,int y){
	ll ans=1;
	for(;y;y>>=1){
		if(y&1)ans*=x;
		x*=x;
	}
	return ans;
}
inline int gcd(int x,int y){
	while(y^=x^=y^=x%=y);
	return x;
}
int t,m,a,b,c,d,tot,p[mxn],f[mxn],phi[mxn];
ll l,r,n,g,ans;
void init(int n){
	phi[1]=1;
	rep(i,2,n){
		if(!f[i])f[i]=p[++tot]=i,phi[i]=i-1;
		rep(j,1,tot){
			if(p[j]>f[i]||p[j]>n/i)break;
			f[p[j]*i]=p[j];
			phi[p[j]*i]=i%p[j]?phi[i]*(p[j]-1):phi[i]*p[j];
		}
	}
}
signed main(){
	init(1e7);
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%d%d",&m,&a,&b,&c,&d);
		l=a==0||b==0?0:power1(m,gcd(a,b));
		r=power1(m,gcd(c,d));
		n=(r-l)/m;
		ans=0;
		g=power(2,n%(md-1));
		rep(k,1,sqrt(m))if(m%k==0){
			if(k&1)ans=(ans+phi[k]*power(g,m/k))%md;
			if(m/k!=k){
				if((m/k)&1)ans=(ans+phi[m/k]*power(g,k))%md;
			}
		}
		printf("%lld\n",(ans*power(m,md-2)%md+md)%md);
	}
	return 0;
}
posted @ 2024-01-20 21:15  zifanwang  阅读(19)  评论(0)    收藏  举报  来源