组合数学之TwelveFold Way

组合数学之TwelveFold Way

题目传送


LLC

  • n个球有标号,m个盒子有标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\) - 否则为 \(ans=A^n_m=C_m^n\cdot A_n^n\),相当于是先从 \(m\) 个盒子取出 \(n\)个盒子,再全排因为球有编号

LLA

  • n个球有标号,m个盒子有标号,盒子没有限制 - 那么每个球都有 \(m\) 种选择 - \(ans=m^n\)

LLB

  • n个球有编号,m个盒子有编号,每个盒子至少放一个球 - 如果 \(n<m,ans=0\)
  • 否则,我们强制有 \(i\) 个盒子为空,其他盒子乱放,需要容斥一下。
  • 首先向LLA一样,答案有 \(m^n\) ,但是这里边含有盒子为空的情况。把一个盒子为空两个盒子为空三个盒子为空...的情况都减掉,但是一个盒子为空里边又包含两个盒子为空三个盒子为空....的情况,会减多,我们加回来两个盒子为空的情况 $$ans=\sum_{i=0}m(-1)i \cdot C_m^i \cdot (m-i)!$$

LUC

  • n个球有标号,m个盒子无标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\) - 否则为 \(ans=1\)

LUB

  • n个球有标号,m个盒子无标号,每个盒子至少放一个球
  • 我们考虑 DP,设 \(f[i][j]\) 表示前 \(i\) 个球放在 \(j\) 个盒子里的方案数$$f[i][j]=f[i-1][j-1]+j \cdot f[i-1][j]$$
  • 因为球有编号,这样顺序DP 起了去重的作用
  • 第二类斯特林数的递推公式 $$S_nm=s_{n-1}+m\cdot S_{n-1}^{m}$$

LUA

  • n个球有标号,m个盒子无标号,盒子无限制 - 我们可以利用LUB,然后枚举空盒子的数量 $$ans=\sum_{i=1}^mf[n][i]$$

ULC

  • n个球无标号,m个盒子有标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\) - 否则为 \(ans=1\)

ULB

  • n个球无标号,m个盒子有标号,每个盒子至少放一个球
  • 隔板法 $$ans=C_{n-1}^{m-1}$$

ULA

  • n个球无标号,m个盒子有标号,盒子无限制
  • 还是隔板法,不过强制几个盒子为空 $$ans=\sum_{i=1}{m}C_{n-1} \cdot C_{m}^{i}$$
  • 不要忘记乘强制选盒子的方案数

UUC

  • n个球无标号,m个盒子无标号,每个盒子至多放一个球
  • 如果 \(n>m,ans=0\)
  • 否则为 \(ans=1\)

UUB

  • n个球无标号,m个盒子无标号,每个盒子至少放一个球
  • 这个不能用隔板法,因为划分出相同数量的盒子,盒子没有编号是相同的。
  • 我们考虑DP,设 \(f[i][j]\) 表示前 \(i\) 个球分到 \(j\) 个盒子里
  • 为了保证不重,我们保证盒子里球的数量单调不降
  • 转移 $$f[i][j]=f[i-1][j-1]+f[i-j][j-1]$$
  • 对于当前的球要么新开一个盒子,要么再之前的盒子基础上都放进去一个
  • 划分数

UUA

  • 对UUB求个和就好了$$ans=\sum_{i=1}^mf[n][i]$$

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define ll long long 
#define mod 998244353
using namespace std;
string s;
ll fac[1000005],f[1005][1005],infac[1000005];
ll n,m;
ll qpow(ll a,ll b){
	ll ans=1ll,res=a;
	while(b){
		if(b&1) ans=(ans*res)%mod;
		res=(res*res)%mod;
		b>>=1;
	}
	return ans;
}
void pre(){
	ll nn=max(n,m);
//	nn=min(nn,1000000);
	fac[0]=1ll;
	for(ll i=1;i<=nn;i++) fac[i]=fac[i-1]*i*1ll%mod;
	infac[nn]=qpow(fac[nn],mod-2);
	
	for(ll i=nn-1;i>=0;i--) infac[i]=infac[i+1]*(i+1)*1ll%mod;
//	for(ll i=0;i<=nn;i++) printf("%lld ",infac[i]);
//	cout<<qpow(fac[nn],2)<<endl;
//	cout<<endl;
}
void work1(){
	if(n<=m) printf("1\n");
	else printf("0\n");
	return ;
}
void work2(){//LLC 
	if(n<=m) printf("%lld",fac[m]*infac[m-n]%mod);
	else  printf("0\n");
//	else if(n==m) printf("")
}
void work3(){
	if(n<=m) printf("%lld",fac[m]*infac[n]%mod*infac[m-n]%mod);
	else printf("0\n");
}
void work4(){//LLB 
	if(n<m){
		printf("0\n");
		return ;
	}
	ll ans=0;
	for(ll i=0;i<=m;i++){
		if(i%2==0) ans=(ans+fac[m]*infac[m-i]%mod*infac[i]%mod*qpow(m-i,n)%mod)%mod;
		else ans=(ans+mod-fac[m]*infac[m-i]%mod*infac[i]%mod*qpow(m-i,n)%mod)%mod;
	}
	printf("%lld\n",ans);
}
void work5(){//LUB 
	if(n<m){
		printf("0\n");
		return ;
	}
	f[0][0]=1;
	//前 i个球放在 j个盒子里的方案数 
	for(ll i=1ll;i<=n;i++)
	  for(ll j=1ll;j<=m;j++)
	    f[i][j]=(f[i-1][j-1]+j*f[i-1][j]%mod)%mod;
	printf("%lld\n",f[n][m]);
}
void work6(){//ULB
	if(n<m){
		printf("0\n");
		return ;
	}
	printf("%lld\n",fac[n-1]*infac[m-1]%mod*infac[n-m]%mod);
}
void work7(){//划分数 UUB 
    if(n<m){
    	printf("0\n");
    	return ;
	}
	f[0][0]=1ll;
	for(ll i=1ll;i<=n;i++)
	  for(ll j=1ll;j<=m;j++)
	    f[i][j]=(f[i-1][j-1]+f[max(i-j,0ll)][j])%mod;
	printf("%lld",f[n][m]%mod);
}
void work8(){//LLA
	printf("%lld",qpow(m,n));
}
void work9(){
	f[0][0]=1;
	//前 i个球放在 j个盒子里的方案数 
	for(ll i=1ll;i<=n;i++)
	  for(ll j=1ll;j<=m;j++)
	    f[i][j]=(f[i-1][j-1]+j*f[i-1][j]%mod)%mod;
	ll ans=0;
	for(ll i=1;i<=m;i++)
	  ans=(ans+f[n][i])%mod;
	printf("%lld",ans);
}
void work10(){//ULA
	ll ans=0;
	for(ll i=0;i<=m;i++)
	  ans=(ans+fac[m]*infac[i]%mod*infac[m-i]%mod*fac[n-1]%mod*infac[i-1]%mod*infac[n-i]%mod)%mod;
	printf("%lld",ans);
}
void work11(){//UUA 
	f[0][0]=1;
	ll ans=0;
	for(ll i=1;i<=n;i++)
	  for(ll j=1;j<=m;j++)
	    f[i][j]=(f[i-1][j-1]+f[max(0ll,i-j)][j])%mod;
	for(ll i=1;i<=m;i++) ans=(ans+f[n][i])%mod;
	printf("%lld",ans);
}
int main(){
	cin>>s;
	scanf("%lld%lld",&n,&m);
	if(n<=1000000&&m<=1000000)pre();
//	cout<<s<<endl;
//    printf("%lld %lld\n",n,m);
	if(s=="LUC") work1();
	else if(s=="LLC") work2();
	else if(s=="UUC") work1();
	else if(s=="ULC") work3();
	else if(s=="LLB") work4();
	else if(s=="LUB") work5();
	else if(s=="ULB") work6();//
	else if(s=="UUB") work7();
	else if(s=="LLA") work8();
	else if(s=="LUA") work9();
	else if(s=="ULA") work10();//
	else if(s=="UUA") work11();
	return 0;
} 
posted @ 2019-11-01 15:46  _Vimin  阅读(647)  评论(0编辑  收藏  举报