网上一堆题解都是置换群+DP的,其实组合数学随便乱搞就可以了。
不考虑洗牌的情况,所有方案数为C(ra+rg+rb,ra)*C(rg+rb,rb)mod p
我们考虑每一种初始状态,通过m种洗牌法可以变为另外m种状态。
题目中有提到,“输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代
替,且对每种洗牌法,都存在一种洗牌法使得能回到原状态。“
我们假设第一次洗牌得到的一种情况x,假设x通过第二次洗牌可以得到y,且y不在第一次洗牌得到的结果集合中。那么y可以变回原状态x,x可以变回原状态,那么由y可以回到初始状态,与y不在集合中矛盾。
也就是说,对于一种状态,有m+1种状态和它打包在一起,是独立的。
那么最终的答案就是C(ra+rg+rb,ra)*C(rg+rb,rb)mod p除一下(m+1)了
注意要写个逆元
#include <bits/stdc++.h>
using namespace std;
void read(int &x)
{
char c;int f=1,ans=0;
c=getchar();
while (c!='-' && (c<'0' || c>'9'))
c=getchar();
while (c=='-')
{
f*=-1;
c=getchar();
}
while (c>='0' && c<='9')
{
ans=ans*10+c-'0';
c=getchar();
}
x=ans*f;
return ;
}
#define maxn (int)1e6
#define ll long long
ll a[maxn];
int p;
ll qpow(ll x,ll m)
{
if (m==0) return 1;
ll tmp=qpow(x,m/2);
tmp=(tmp*tmp)%p;
if (m%2==1) tmp=(tmp*x)%p;
return tmp;
}
ll getc(ll n,ll m)
{
if (m>n) return 0;
return (a[n]*qpow(a[m],p-2))%p*qpow(a[n-m],p-2)%p;
}
ll lucas(long long n,long long m)
{
if (m==0) return 1;
return (getc(n%p,m%p)*lucas(n/p,m/p))%p;
}
int main()
{
int n,m,aa,b,c;
read(aa);read(b);read(c);read(m);read(p);
ll t=1;
ll ans=1;
n=aa+b+c;
a[1]=1;
for (int i=2;i<=p;i++)
a[i]=(a[i-1]*i)%p;
ans=ans*lucas(n,aa)%p;
ans=ans*lucas(n-aa,b)%p;
ans=ans*qpow(m+1,p-2)%p;
cout<<ans<<endl;
return 0;
}
其实自己置换学得很菜,学好了再回来补下置换解法的坑吧。