题目
#1.Burnside引理
Burnside引理与Polya定理
题解
//d[i]表示第i个循环的长度,b[i]是标记
#include<bits/stdc++.h>
using namespace std;
int f[22][22][22],i,b[62],a[62][62],n,m,ans,sr,sb,sg,M,x,d[62],j,y;
int dp(int x){
memset(b,0,sizeof(b));
int sum=0,p;
for (int i=1;i<=n;i++)
if (!b[i]){
d[++sum]=0;
for (p=i;!b[p];p=a[x][p]) d[sum]++,b[p]=1;
}
memset(f,0,sizeof(f));
f[0][0][0]=1;
//刚开始把下面三个循环改成>=d[h],想省略三个判断,但事实上不能这么做
for (int h=1;h<=sum;h++)
for (int i=sr;i>=0;i--)
for (int j=sb;j>=0;j--)
for (int k=sg;k>=0;k--){
if (i>=d[h]) f[i][j][k]=(f[i][j][k]+f[i-d[h]][j][k])%M;
if (j>=d[h]) f[i][j][k]=(f[i][j][k]+f[i][j-d[h]][k])%M;
if (k>=d[h]) f[i][j][k]=(f[i][j][k]+f[i][j][k-d[h]])%M;
}
return f[sr][sb][sg];
}
void ex_gcd(int a,int b,int &x,int &y){
if (!b){
x=1;y=0;
return;
}
ex_gcd(b,a%b,y,x);
y-=a/b*x;
}
int main(){
scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&M);
n=sr+sb+sg;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++) scanf("%d",&a[i][j]);
m++;
for (i=1;i<=n;i++) a[m][i]=i;
for (i=1;i<=m;i++) ans=(ans+dp(i))%M;
ex_gcd(m,M,x,y);
x=(x+M)%M;
printf("%d",ans*x%M);
}
#2.组合数学
题解
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int ans,n,sr,sb,sg,m,M,i;
ll t;
int pm(int x,int y){
int z=1;
for (;y;y>>=1,x=x*x%M)
if (y&1) z=z*x%M;
return z;
}
int main(){
scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&M);
n=sr+sb;
for (i=t=1;i<=sr;i++) t=t*(n-i+1)/i;//刚开始习惯性写成*=,好***
ans=t%M;
n+=sg;
for (i=t=1;i<=sg;i++) t=t*(n-i+1)/i;
ans=t%M*ans%M;
printf("%d",ans*pm(m+1,M-2)%M);
}
注:本题因为模数是质数,所以费马小定理和exgcd都可以求逆元