【题解】礼物 | [洛谷 P4916] 魔力环【20210113 省选模拟赛】【Burnside引理 容斥 组合数】
题目链接(加强,略有不同)
题意
问有多少种本质不同的项链,满足:
- 有 \(n\) 个黑色珠子,\(m\) 个白色珠子;
- 连续的白色珠子不超过 \(k\) 个。
旋转同构算作相同,翻转同构算作不同。
\(n,m\leq 10^6\),\(T\leq 5\) 组询问。
题解
Burnside 引理,于是不考虑本质不同的限制。
先假设项链从黑色珠子开始,最后乘上 \(\dfrac{n'+m'}{n'}\) 即可。考虑项链是由许多 黑+白*i
的段拼成的,故答案为:
\[[x^{m+n}] (x+x^2+\cdots +x^{k+1})^n=[x^m] (x^0+x^1+\cdots +x^k)^n
\]
考虑其组合意义:用 \(n\) 个不大于 \(k\) 的数凑出 \(m\),于是容斥枚举多少个数大于 \(k\):
\[\sum_{i=0}^n (-1)^i\dbinom{n}{i}\dbinom{m-1-i(k+1)}{n-1}
\]
#include<bits/stdc++.h>
using namespace std;
const int N=4e6,mod=998244353,G=3;
int qpow(int x,int y){
int ans=1;
while(y){
if(y&1)ans=ans*1ll*x%mod;
x=x*1ll*x%mod;
y>>=1;
}
return ans;
}
int fac[N],ifac[N];
int binom(int n,int m){
if(m<0||m>n)return 0;
return fac[n]*1ll*ifac[m]%mod*ifac[n-m]%mod;
}
int t=0;
int calc(int n,int m,int k){
int ans=0;
m=n-m;
for(int i=0;i*(k+1)<n&&i<=m;i++)
ans=(ans+(i&1?mod-1ll:1ll)*binom(m,i)%mod*binom(n-1-i*(k+1),m-1))%mod;
ans=ans*1ll*t%mod;
return ans;
}
int gcd(int x,int y){
return x?gcd(y%x,x):y;
}
int q[N];
int main(){
int T;cin>>T;
while(T--){
int n,m,k;
cin>>n>>m>>k;
t=qpow(n-m,mod-2)*1ll*n%mod;
if(n==m){
printf("%d\n",k==n);
continue;
}
fac[0]=1;for(int i=1;i<=n+m;i++)fac[i]=fac[i-1]*1ll*i%mod;
ifac[n+m]=qpow(fac[n+m],mod-2);
for(int i=n+m-1;i>=0;i--)ifac[i]=ifac[i+1]*(i+1ll)%mod;
int sum=0,g=gcd(n,m);
for(int i=1;i<=n;i++)q[i]=0;
for(int i=1;i<=n;i++){
int t=n/gcd(n,i);
if(m%t)continue;
if(n%i==0)
sum=(sum+(q[t]=calc(n/t,m/t,k)))%mod;
else
sum=(sum+q[t])%mod;
}
printf("%d\n",sum*1ll*qpow(n,mod-2)%mod);
}
}