題目
#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都可以求逆元