#排列组合,容斥#洛谷 5684 [CSPJX2019]非回文串

题目


分析

那显然就是\(n!\)减去回文串的方案数
首先如果有超过一个出现奇数次字母那肯定不存在回文串
如果有且仅有一个首先要在次数中选择一个然后其它当偶数处理
偶数那就是首先字母位置选好但顺序可以任意打乱,所以就是多重集的排列数


代码

#include <cstdio>
#define rr register
using namespace std;
const int mod=1000000007,N=2011;
int n,rt,fac[N],inv[N],c[N],ans; char s[N];
signed main(){
	scanf("%d%s",&n,s+1),rt=-1;
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	for (rr int i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	for (rr int i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
	for (rr int i=1;i<=n;++i) ++c[s[i]^96];
	for (rr int i=1;i<27;++i)
	if (c[i]&1){
		if (~rt) return !printf("%d",fac[n]);
		    else rt=i;
	}
	ans=1ll*fac[n>>1]*(~rt?c[rt]:1)%mod; for (rr int i=1;i<27;++i) c[i]>>=1;
	for (rr int i=1;i<27;++i) ans=1ll*ans*fac[c[i]<<1]%mod*inv[c[i]]%mod;
	ans=fac[n]<ans?fac[n]-ans+mod:fac[n]-ans;
	return !printf("%d",ans);
}
上一篇:luogu 6046 纯粹容器 期望dp


下一篇:「题解」Solution loj #10238 / BZOJ 3907