题解:P7504 「HMOI R1」可爱的德丽莎
数论题,先化式子。
可以发现左右两个式子是相同的,我们讨论其中一个。
看到
把
发现
把
似乎没什么好化的了,现在变成了一个前缀和的形式,于是我们考虑杜教筛。
发现若
接下来我们需要求
发现后面的
对于
于是我们可以在可接受的时间内计算出
下附代码:
#include<iostream>
#include<cstdio>
#include<unordered_map>
#define int long long
using namespace std;
const int mod=998244353;
int n,k,inv6,mu[1000005],p[1000005],phi[1000005],tot,f[1000005],g[1000005],fg[1000005],v[1000005],mul[1000005],cur;
long long ans=1;
bool isp[1000005];
inline int f_pow(long long a,int b){
long long res=1;
while(b>0){
if(b&1) res*=a,res%=mod;
a*=a,a%=mod,b>>=1;
}
return res;
}
inline int Sum1(int x){
return 1ll*x*(x+1)/2%mod;
}
inline int Sum2(int x){
return 1ll*x*(x+1)%mod*(2*x+1)%mod*inv6%mod;
}
inline int getmu(int x){
int res=0;
for(int i=2;i<=x/i;i++){
if(x%i==0){
int cnt=0;
while(x%i==0) cnt++,x/=i;
if(cnt>=2) return 0;
res++;
}
}
if(x>1) res++;
return (res&1?-1:1);
}
unordered_map<int,int>mpf,mpg,mpfg;
inline void getprime(){
tot=0;mu[1]=1;phi[1]=1;
for(int i=2;i<=1000000;i++) isp[i]=1;
for(int i=2;i<=1000000;i++){
if(isp[i]) p[++tot]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=tot&&p[j]*i<=1000000;j++){
isp[i*p[j]]=0;
mu[i*p[j]]=mu[i]*mu[p[j]];
phi[i*p[j]]=phi[i]*phi[p[j]];
if(i%p[j]==0){
mu[i*p[j]]=0;
phi[i*p[j]]=phi[i]*p[j];
break;
}
}
}
}
inline void getfg(){
cur=0;f[1]=1,g[1]=1,fg[1]=1;
for(int i=2;i<=1000000;i++) f[i]=0,g[i]=0,fg[i]=0;
for(int i=2;i<=1000000;i++){
if(isp[i]&&k%i!=0) f[i]=1ll*i*phi[i]%mod,g[i]=i,fg[i]=1ll*i*i%mod;
for(int j=1;j<=tot&&p[j]*i<=1000000;j++){
if(f[i]&&k%p[j]!=0) f[i*p[j]]=1ll*i*p[j]*phi[i*p[j]]%mod;
g[i*p[j]]=1ll*g[i]*g[p[j]]%mod;
fg[i*p[j]]=1ll*fg[i]*fg[p[j]]%mod;
if(i%p[j]==0){
break;
}
}
}
for(int i=1;i<=1000000;i++){
f[i]+=f[i-1];f[i]%=mod;
g[i]+=g[i-1];g[i]%=mod;
fg[i]+=fg[i-1];fg[i]%=mod;
}
for(int i=1;i<=k/i;i++){
if(k%i==0){//提前记录 k 的因数
v[++cur]=i;mul[cur]=mu[i];
if(1ll*i*i!=k) v[++cur]=k/i,mul[cur]=getmu(k/i);
}
}
}
inline int getgsum(int n){
if(n<=1000000) return g[n];
if(mpg.find(n)!=mpg.end()) return mpg[n];
long long sum=0;
for(int i=1;i<=cur;i++){
sum+=1ll*mul[i]*v[i]*Sum1(n/v[i])%mod;
// sum=(sum%mod+mod)%mod;
}
sum=(sum%mod+mod)%mod;
mpg[n]=sum;
return sum;
}
inline int getfgsum(int n){
if(n<=1000000) return fg[n];
if(mpfg.find(n)!=mpfg.end()) return mpfg[n];
long long sum=0;
for(int i=1;i<=cur;i++){
sum+=1ll*mul[i]*v[i]*v[i]%mod*Sum2(n/v[i])%mod;
// sum=(sum%mod+mod)%mod;
}
sum=(sum%mod+mod)%mod;
mpfg[n]=sum;
return sum;
}
inline int getfsum(int n){
if(n<=1000000) return f[n];
if(mpf.find(n)!=mpf.end()) return mpf[n];
long long sum=getfgsum(n);
int l=2,r=0;
while(l<=n){
r=n/(n/l);
sum-=1ll*(getgsum(r)-getgsum(l-1))*getfsum(n/l)%mod;
// sum=(sum%mod+mod)%mod;
l=r+1;
}
sum=(sum%mod+mod)%mod;
mpf[n]=sum;
return sum;
}
inline int crychic(){
mpf.clear();mpg.clear();mpfg.clear();getfg();
return 1ll*(getfsum(n)+1)*f_pow(2,mod-2)%mod;
}
signed main(){
cin>>n>>k;inv6=f_pow(6,mod-2);getprime();
ans*=crychic();
cin>>k;ans*=crychic();ans%=mod;
cout<<ans<<endl;
return 0;
}