題意
給出,問有多少個長度爲的環,環上恰有個黑珠子和個白珠子,且不存在一段連續的黑珠子的長度超過。兩個環相等當且僅當他們循環同構。
分析
首先根據Burnside引理,設表示週期爲的合法序列數量,則
顯然必然也要是的約數,考慮如何計算
問題變成要將個黑珠子插入到個白珠子組成的縫隙當中,滿足每個縫隙放不超過個黑珠子,求有多少個循環同構的方案。
考慮枚舉第一個白珠子和最後一個白珠子之間的黑珠子方案,則
其中表示將個相同的球放入個不同的盒子中,且每個盒子中的球不能找過個的方案,計算顯然可以用容斥在的複雜度內求出。
所以複雜度爲
於是總的複雜度爲
代碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long LL;
const int N=100005;
const int MOD=998244353;
int n,m,k,jc[N*2],ny[N*2];
int ksm(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=(LL)ans*x%MOD;
x=(LL)x*x%MOD;y>>=1;
}
return ans;
}
int gcd(int x,int y)
{
if (!y) return x;
else return gcd(y,x%y);
}
int get_phi(int n)
{
int ans=n;
for (int i=2;i*i<=n;i++)
if (n%i==0)
{
ans=ans/i*(i-1);
while (n%i==0) n/=i;
}
if (n>1) ans=ans/n*(n-1);
return ans;
}
int C(int n,int m)
{
return (LL)jc[n]*ny[m]%MOD*ny[n-m]%MOD;
}
int calc(int n,int m)
{
if (!n) return !m?1:0;
int ans=0;
for (int i=0;i<=n&&(k+1)*i<=m;i++)
if (i&1) (ans+=MOD-(LL)C(n,i)*C(m-(k+1)*i+n-1,n-1)%MOD)%=MOD;
else (ans+=(LL)C(n,i)*C(m-(k+1)*i+n-1,n-1)%MOD)%=MOD;
return ans;
}
int solve(int n,int m)
{
int ans=0;
for (int i=0;i<=std::min(m,k);i++) (ans+=(LL)(i+1)*calc(n-1,m-i)%MOD)%=MOD;
return ans;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
jc[0]=jc[1]=ny[0]=ny[1]=1;
for (int i=2;i<=n+m;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD;
for (int i=2;i<=n+m;i++) ny[i]=(LL)ny[i-1]*ny[i]%MOD;
if (n==m) {printf("%d\n",k>=n?1:0);return 0;}
int ans=0,d=gcd(n,m);
for (int i=1;i*i<=d;i++)
if (d%i==0)
{
(ans+=(LL)solve((n-m)/i,m/i)*get_phi(i)%MOD)%=MOD;
if (d/i!=i) (ans+=(LL)solve((n-m)/(d/i),m/(d/i))*get_phi(d/i)%MOD)%=MOD;
}
printf("%d\n",(LL)ans*ksm(n,MOD-2)%MOD);
return 0;
}