题解 P4916 【魔力环】
考虑
考虑如何计算不动点的数量,为了方便首先把
现在把要求的东西重新拿出来定义一下,即有
我们把
那么枚举第一个球之前和最后一个球之后这两段一共放了多少个球,然后前后分配一下,所以方案数就是:
那么这样子总的复杂度就是
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 1000010
#define MOD 998244353
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
bool zs[MAX];
int pri[MAX],phi[MAX],tot;
int jc[MAX<<1],inv[MAX<<1],jv[MAX<<1];
void pre(int n)
{
phi[1]=1;
for(int i=2;i<=n;++i)
{
if(!zs[i])pri[++tot]=i,phi[i]=i-1;
for(int j=1;j<=tot&&i*pri[j]<=n;++j)
{
zs[i*pri[j]]=true;
if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
jc[0]=jv[0]=inv[0]=inv[1]=1;
for(int i=2;i<=n+n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n+n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
for(int i=1;i<=n+n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
}
int Choose(int n,int m){if(n<m||n<0||m<0)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
int Put(int m,int n){if(m<0)return 0;return Choose(n+m-1,n-1);}
int n,m,K,p[MAX];
int Insert(int m,int n,int k)
{
int ret=0;if(m<0)return 0;
for(int i=0,d=1;i<=n;++i,d=MOD-d)
if(m>=1ll*i*(k+1))ret=(ret+1ll*Put(m-i*(k+1),n)*Choose(n,i)%MOD*d)%MOD;
else break;
return ret;
}
int Calc(int d)
{
int N=n/d,C=m/d,ret=0;
if(C<=K)return Choose(N,C);
if(K==1)return (Choose(N-C+1,C)+MOD-Choose(N-C-1,C-2))%MOD;
for(int i=0;i<=K;++i)
ret=(ret+1ll*(i+1)*Insert(C-i,N-C-1,K))%MOD;
return ret;
}
int main()
{
n=read();m=read();K=read();pre(n);
if(n==m){if(K==n)puts("1");else puts("0");return 0;}
if(!m){puts("1");return 0;}
int g=__gcd(n,m),ans=0;
for(int i=1;i*i<=g;++i)
if(g%i==0)
{
ans=(ans+1ll*Calc(i)*phi[i])%MOD;
if(i*i!=g)ans=(ans+1ll*Calc(g/i)*phi[g/i])%MOD;
}
ans=1ll*ans*fpow(n,MOD-2)%MOD;
printf("%d\n",ans);
}