首页 > 代码库 > HNOI2008Cards

HNOI2008Cards

暗了一下polya和burnside定理,感觉还行(就是不会证……)

这题用的是burnside

ans=在每个置换群下不动的方案数之和除以置换数

这题有个难点在取模

关于对p(p为素数)取模(涉及到了除法),我总结了两种方法:

已知x mop p=y,要求x/z mod p=?

大体思路是利用乘法逆,将/z转换成*z的逆元即可

一、利用费马小定理

     z^p-1 mod p=1 

     所以z的逆元=power_mod(z,p-2,p)

二、利用拓展欧几里德算法,即exgcd(z,p,x,y) 

      while x<0 do inc(x,p)

      事实上,这也是乘法逆的思想

      exgcd(z,p,x,y) 这实际上是在解同余方程zx mod p=1

      x不就是z的逆元吗

但是当p不是素数时,应该怎么办呢?

在做noi2002robot的时候,我运用了一种特殊的方法,最后需要求x>>1 mod p=?

我在过程中始终对p取模,到最后感觉做不下去了

后来我灵机一动,想到了多取一位 在过程中mod 10p  

这样 最后输出的时候再mod p 答案就正确了

不知道这样的方法能否应用在更广泛的地方……

ps:刚才试了一下此题

    在过程中一直对m*p取模,最后ans div m 再对p取模,竟然AC了 

    原理在哪里?

代码:

神牛Green Clouds 的代码(费马小定理):

 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4   5 using namespace std ; 6   7 const int maxn =21; 8   9 int sr , sb , sg , m , mod , f[ maxn ][ maxn ][ maxn ], a[ maxn *3], n ;10 bool used[ maxn *3];11 int v[ maxn *3], cnt , ans =0;12  13 void update(int&num ,int val ){14     ( num += val )%= mod ;15 }16  17 int power(int val ,int times ){18     int rec =1;19     for(; times ; times >>=1){20         if( times &1)( rec *= val )%= mod ;21         ( val *= val )%= mod ;22     }23     return rec ;24 }25  26 int main(  ){27     scanf("%d%d%d%d%d",&sr ,&sb ,&sg ,&m ,&mod );28     n = sr + sb + sg ;29     for(int w =0; w ++< m +1;){30         if( w < m +1)for(int i =0; i ++< n ;)scanf("%d", a + i );31         else for(int i =0; i ++< n ;) a[ i ]= i ;32         memset( used ,false,sizeof( used ));33         cnt =0;34         for(int i =0; i ++< n ;)if(! used[ i ]){35             v[++ cnt ]=0;36             for(int j = i ;! used[ j ]; j = a[ j ]){37                 ++ v[ cnt ], used[ j ]=true;38             }39         }40         memset( f ,0,sizeof( f ));41         f[0][0][0]=1;42         for(int h =0; h ++< cnt ;){43             for(int i = sr ; i >=0;-- i ){44                 for(int j = sb ; j >=0;-- j ){45                     for(int k = sg ; k >=0;-- k ){46                         if( i >= v[ h ])update( f[ i ][ j ][ k ], f[ i - v[ h ]][ j ][ k ]);47                         if( j >= v[ h ])update( f[ i ][ j ][ k ], f[ i ][ j - v[ h ]][ k ]);48                         if( k >= v[ h ])update( f[ i ][ j ][ k ], f[ i ][ j ][ k - v[ h ]]);49                     }50                 }51             }52         }53         update( ans , f[ sr ][ sb ][ sg ]);54     }55     ( ans *=power( m +1, mod -2))%= mod ;56     printf("%d\n", ans );57     return 0;58 }
View Code 

exgcd:

 1 var s1,s2,s3,n,m,p,ans,i,j,x,y:longint; 2     a:array[0..70,0..70] of longint; 3     f:array[0..25,0..25,0..25] of longint; 4 function mo(x:longint):longint; 5  begin 6    mo:=x mod (p); 7  end; 8 procedure init; 9  begin10    readln(s1,s2,s3,m,p);11    n:=s1+s2+s3;12    for i:=1 to m do13     for j:=1 to n do14      read(a[i,j]);15    inc(m);16    for i:=1 to n do a[m,i]:=i;17  end;18 function dp(x:longint):longint;19  var i,j,k,tot,y,h,num:longint;20      v:array[0..70] of boolean;21      d:array[0..70] of longint;22  begin23    tot:=0;24    fillchar(v,sizeof(v),false);25    for i:=1 to n do26     if not(v[i]) then27      begin28        num:=1;29        v[i]:=true;30        y:=i;31        while a[x,y]<>i do32         begin33          y:=a[x,y];34          v[y]:=true;35          inc(num);36         end;37        inc(tot);38        d[tot]:=num;39      end;40    fillchar(f,sizeof(f),0);41    f[0,0,0]:=1;42    for h:=1 to tot do43     for i:=s1 downto 0 do44      for j:=s2 downto 0 do45       for k:=s3 downto 0 do46        begin47         if i>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i-d[h],j,k]);48         if j>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j-d[h],k]);49         if k>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j,k-d[h]]);50        end;51    exit(f[s1,s2,s3]);52    end;53 procedure exgcd(a,b:longint;var x,y:longint);54  var t:longint;55  begin56  if a=1 then begin x:=1;y:=0;exit;end;57  exgcd(b,a mod b,x,y);58  t:=x;x:=y;y:=t-(a div b)*x;59  end;60 procedure main;61  begin62    ans:=0;63    for i:=1 to m do64     ans:=mo(ans+dp(i));65    exgcd(m,p,x,y);66    while x<0 do inc(x,p);67    writeln((ans*x) mod p);68  end;69 begin70   init;71   main;72 end.         
View Code

m*p:

 1 var s1,s2,s3,n,m,p,ans,i,j,x,y:longint; 2     a:array[0..70,0..70] of longint; 3     f:array[0..25,0..25,0..25] of longint; 4 function mo(x:longint):longint; 5  begin 6    mo:=x mod (m*p); 7  end; 8 procedure init; 9  begin10    readln(s1,s2,s3,m,p);11    n:=s1+s2+s3;12    for i:=1 to m do13     for j:=1 to n do14      read(a[i,j]);15    inc(m);16    for i:=1 to n do a[m,i]:=i;17  end;18 function dp(x:longint):longint;19  var i,j,k,tot,y,h,num:longint;20      v:array[0..70] of boolean;21      d:array[0..70] of longint;22  begin23    tot:=0;24    fillchar(v,sizeof(v),false);25    for i:=1 to n do26     if not(v[i]) then27      begin28        num:=1;29        v[i]:=true;30        y:=i;31        while a[x,y]<>i do32         begin33          y:=a[x,y];34          v[y]:=true;35          inc(num);36         end;37        inc(tot);38        d[tot]:=num;39      end;40    fillchar(f,sizeof(f),0);41    f[0,0,0]:=1;42    for h:=1 to tot do43     for i:=s1 downto 0 do44      for j:=s2 downto 0 do45       for k:=s3 downto 0 do46        begin47         if i>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i-d[h],j,k]);48         if j>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j-d[h],k]);49         if k>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j,k-d[h]]);50        end;51    exit(f[s1,s2,s3]);52    end;53 procedure main;54  begin55    ans:=0;56    for i:=1 to m do57     ans:=mo(ans+dp(i));58    writeln((ans div m) mod p);59  end;60 begin61   init;62   main;63 end.   64     
View Code