这道题做了挺久的...感觉还是对于Burnside引理理解的不够透彻吧。

    Burnside引理:

      L=1/|G|*(c1+c2+...ck),ci表示第i种置换的不动置换类。如置换:(123)(45)(6)中的不动置换类只有(6)一个。

    这道题不能用Polya定理,因为每种颜色有具体的数量要求,不能任意染色。

    题目中给的洗牌方法,很显然就是一个个置换了。那么不动置换类要怎么求呢?

    颜色相同的看上去也一样,所以如果置换后位置上的颜色与原位置的颜色相同,也算是不动置换类

    而这道题需要思考的是,我们应该怎样把染色方案带到公式里去。

    答案是,将一个染色方案看做一个元素。

    即这道题中的不动置换类为经过该种置换后仍然不变的一个染色方案。

    那么不动置换类的个数即ci也就是满足在经过i种置换后每一位上颜色都不变的染色方案总数。

    则每个循环中要染同一种颜色,可以用01背包来计算方案数。

    最后不能忘记最重要也是最基础的一个置换即(1)(2)(3)...(n)这个置换。

    实现的过程中需要用到求乘法逆元。稍加注意即可。

     

program bzoj1004;
const maxn=;
var i,j,t1,t2,t3:longint;
s1,s2,s3,m,p,n,ans,tot,sum,x:int64;
f:array[-..maxn,-..maxn,-..maxn]of int64;
vis:array[-..maxn]of boolean;
a:array[-..maxn]of longint; function ex_Euclid(a,b:int64;var x,y:int64):int64;
var t:int64;
begin
if b= then
begin
x:=;y:=;exit(a);
end else
begin
ex_Euclid:=ex_Euclid(b,a mod b,x,y);
t:=x;x:=y;y:=t-(a div b)*y;
end;
end; function inverse(a:int64):int64;
var x,y,tem,d:int64;
begin
d:=ex_Euclid(a,p,x,y);
if d<> then exit(-) else
begin
if x< then
begin
tem:=(-x) div p;
x:=x+tem*p;y:=y-tem*a;
end;
if x< then
begin
x:=x+p;y:=y-p;
end;
end;
exit(x);
end; begin
readln(s1,s2,s3,m,p);n:=s1+s2+s3;
ans:=;
for i:= to n do ans:=(ans*i) mod p;
for i:= to s1 do ans:=(ans*inverse(i)) mod p;
for i:= to s2 do ans:=(ans*inverse(i)) mod p;
for i:= to s3 do ans:=(ans*inverse(i)) mod p;
for i:= to m do
begin
fillchar(f,sizeof(f),);
fillchar(vis,sizeof(vis),true);
f[,,]:=;sum:=;
for j:= to n do read(a[j]);readln;
for j:= to n do if vis[j] then
begin
tot:=;
x:=a[j];vis[j]:=false;
while x<>j do
begin
inc(tot);
vis[x]:=false;
x:=a[x];
end;
inc(sum,tot);
for t1:= to sum do
for t2:= to sum-t1 do
begin
t3:=sum-t1-t2;
if t1-tot>= then f[t1,t2,t3]:=(f[t1,t2,t3]+f[t1-tot,t2,t3]) mod p;
if t2-tot>= then f[t1,t2,t3]:=(f[t1,t2,t3]+f[t1,t2-tot,t3]) mod p;
if t3-tot>= then f[t1,t2,t3]:=(f[t1,t2,t3]+f[t1,t2,t3-tot]) mod p;
end;
end;
end;
ans:=(ans*inverse(m+)) mod p;
writeln(ans);
end.

 

      

05-02 18:01