【Polya定理】BZOJ1488
阿新 • • 發佈:2018-12-09
分析:
據說很板的Polya定理的題。。。
可能我學了假的Polya。。。
首先回顧一下Polya定理的內容: 對n個染色位置的本質不同的染色方案數(即不能通過置換得到另一染色方案):
這裡的k是指一種置換,指這種置換的迴圈數。當然,這個基礎公式很多時候並不實用,因此還有一種計算方式:
這個就更加粗暴了,p是某種置換的迴圈個數,指迴圈個數為個的置換有多少個。 這題就需要這個公式。現在這題最大的難點是:置換是在點上的,然而染色是在邊上的。
因此問題就是:如何處理點置換與邊置換的對應關係。
把邊置換分為兩部分來看:邊的兩端在同一個點迴圈內的,邊的兩端在不同的點迴圈內的。
第一種情況:
邊迴圈大小為點迴圈大小的一半(向下取整)。 證明據說很直觀: 列舉這個迴圈內的點置換 那麼當時,就可以在中找一個與它相同。
第二種情況:
這兩個點迴圈之間的邊迴圈大小,為兩個點迴圈大小的GCD。 證明據說也很簡單。。可以畫圖來證明? 附一個大佬的部落格
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 65
#define MOD 997
using namespace std;
int fsp(int x,int y){
int res=1;
while(y){
if(y&1)
res=res*x%MOD;
x=x*x%MOD;
y>>=1 ;
}
return res;
}
int gcd(int x,int y){
if(y==0)
return x;
return gcd(y,x%y);
}
int a[MAXN],b[MAXN],fac[MAXN],ans,n,m;
void solve(int x,int sum,int cnt){
if(sum==0){
int res=0,add=1;
for(int i=1;i<=cnt;i++){
res+=(a[i]/2*b[i]+b[i]*(b[i]-1)/2*a[i])%(MOD-1);
add=add*fac[b[i]]%MOD*fsp(a[i],b[i])%MOD;
for(int j=i+1;j<=cnt;j++)
res+=b[i]*b[j]*gcd(a[i],a[j]);
res%=(MOD-1);
}
add=fac[n]*fsp(add,MOD-2)%MOD;
ans+=add*fsp(m,res)%MOD;
ans%=MOD;
return ;
}
if(x==0)
return ;
for(int i=1;i*x<=sum;i++){
a[cnt+1]=x;
b[cnt+1]=i;
solve(x-1,sum-i*x,cnt+1);
}
solve(x-1,sum,cnt);
}
int main(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
SF("%d%d",&n,&m);
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%MOD;
solve(n,n,0);
ans*=fsp(fac[n],MOD-2);
ans%=MOD;
PF("%d",ans);
}