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 的代码(费马小定理):
#include <cstdio>
#include <algorithm>
#include <cstring> using namespace std ; const int maxn =; int sr , sb , sg , m , mod , f[ maxn ][ maxn ][ maxn ], a[ maxn *], n ;
bool used[ maxn *];
int v[ maxn *], cnt , ans =; void update(int&num ,int val ){
( num += val )%= mod ;
} int power(int val ,int times ){
int rec =;
for(; times ; times >>=){
if( times &)( rec *= val )%= mod ;
( val *= val )%= mod ;
}
return rec ;
} int main( ){
scanf("%d%d%d%d%d",&sr ,&sb ,&sg ,&m ,&mod );
n = sr + sb + sg ;
for(int w =; w ++< m +;){
if( w < m +)for(int i =; i ++< n ;)scanf("%d", a + i );
else for(int i =; i ++< n ;) a[ i ]= i ;
memset( used ,false,sizeof( used ));
cnt =;
for(int i =; i ++< n ;)if(! used[ i ]){
v[++ cnt ]=;
for(int j = i ;! used[ j ]; j = a[ j ]){
++ v[ cnt ], used[ j ]=true;
}
}
memset( f ,,sizeof( f ));
f[][][]=;
for(int h =; h ++< cnt ;){
for(int i = sr ; i >=;-- i ){
for(int j = sb ; j >=;-- j ){
for(int k = sg ; k >=;-- k ){
if( i >= v[ h ])update( f[ i ][ j ][ k ], f[ i - v[ h ]][ j ][ k ]);
if( j >= v[ h ])update( f[ i ][ j ][ k ], f[ i ][ j - v[ h ]][ k ]);
if( k >= v[ h ])update( f[ i ][ j ][ k ], f[ i ][ j ][ k - v[ h ]]);
}
}
}
}
update( ans , f[ sr ][ sb ][ sg ]);
}
( ans *=power( m +, mod -))%= mod ;
printf("%d\n", ans );
return ;
}
exgcd:
var s1,s2,s3,n,m,p,ans,i,j,x,y:longint;
a:array[..,..] of longint;
f:array[..,..,..] of longint;
function mo(x:longint):longint;
begin
mo:=x mod (p);
end;
procedure init;
begin
readln(s1,s2,s3,m,p);
n:=s1+s2+s3;
for i:= to m do
for j:= to n do
read(a[i,j]);
inc(m);
for i:= to n do a[m,i]:=i;
end;
function dp(x:longint):longint;
var i,j,k,tot,y,h,num:longint;
v:array[..] of boolean;
d:array[..] of longint;
begin
tot:=;
fillchar(v,sizeof(v),false);
for i:= to n do
if not(v[i]) then
begin
num:=;
v[i]:=true;
y:=i;
while a[x,y]<>i do
begin
y:=a[x,y];
v[y]:=true;
inc(num);
end;
inc(tot);
d[tot]:=num;
end;
fillchar(f,sizeof(f),);
f[,,]:=;
for h:= to tot do
for i:=s1 downto do
for j:=s2 downto do
for k:=s3 downto do
begin
if i>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i-d[h],j,k]);
if j>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j-d[h],k]);
if k>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j,k-d[h]]);
end;
exit(f[s1,s2,s3]);
end;
procedure exgcd(a,b:longint;var x,y:longint);
var t:longint;
begin
if a= then begin x:=;y:=;exit;end;
exgcd(b,a mod b,x,y);
t:=x;x:=y;y:=t-(a div b)*x;
end;
procedure main;
begin
ans:=;
for i:= to m do
ans:=mo(ans+dp(i));
exgcd(m,p,x,y);
while x< do inc(x,p);
writeln((ans*x) mod p);
end;
begin
init;
main;
end.
m*p:
var s1,s2,s3,n,m,p,ans,i,j,x,y:longint;
a:array[..,..] of longint;
f:array[..,..,..] of longint;
function mo(x:longint):longint;
begin
mo:=x mod (m*p);
end;
procedure init;
begin
readln(s1,s2,s3,m,p);
n:=s1+s2+s3;
for i:= to m do
for j:= to n do
read(a[i,j]);
inc(m);
for i:= to n do a[m,i]:=i;
end;
function dp(x:longint):longint;
var i,j,k,tot,y,h,num:longint;
v:array[..] of boolean;
d:array[..] of longint;
begin
tot:=;
fillchar(v,sizeof(v),false);
for i:= to n do
if not(v[i]) then
begin
num:=;
v[i]:=true;
y:=i;
while a[x,y]<>i do
begin
y:=a[x,y];
v[y]:=true;
inc(num);
end;
inc(tot);
d[tot]:=num;
end;
fillchar(f,sizeof(f),);
f[,,]:=;
for h:= to tot do
for i:=s1 downto do
for j:=s2 downto do
for k:=s3 downto do
begin
if i>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i-d[h],j,k]);
if j>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j-d[h],k]);
if k>=d[h] then f[i,j,k]:=mo(f[i,j,k]+f[i,j,k-d[h]]);
end;
exit(f[s1,s2,s3]);
end;
procedure main;
begin
ans:=;
for i:= to m do
ans:=mo(ans+dp(i));
writeln((ans div m) mod p);
end;
begin
init;
main;
end.
HNOI2008Cards的更多相关文章
- BZOJ1004 HNOI2008Cards(Burnside引理+动态规划)
直接给了一个置换群(当然要自己手动加上不洗牌的情况).考虑求不动点数量即可.对于一个置换,求出所有循环的长度,然后设f[i][x][y]为给前i个循环着色后,用了x张红色卡片.y张绿色卡片的方案数,d ...
随机推荐
- 用minicom 产看 usb的串口
1 用命令 sudo apt-get install minicom 安装 2 用 minicom -s 进行配置 往下选择 Seral port setup: 然后输入 A :选择自己的 ...
- 不得不知道的Python字符串编码相关的知识
开发经常会遇到各种字符串编码的问题,例如报错SyntaxError: Non-ASCII character 'ascii' codec can't encode characters in posi ...
- Have Fun with Numbers (大数)
Notice that the number 123456789 is a 9-digit number consisting exactly the numbers from 1 to 9, wit ...
- PHP微信开发代码
1,SAE上申请服务器 2,绑定测试账号 3,Token验证 <?php /* http://www.cnblogs.com/xrhou12326/ CopyRight 2014 All Rig ...
- Sugarcrm Email Integration
Introdurce http://www.sugarcrm.com/feature/email-integration Tutor http://www.youtube.com/watch?v=BQ ...
- Microsoft.Web.Administration in IIS
http://blogs.msdn.com/b/carlosag/archive/2006/04/17/microsoftwebadministration.aspx 最好使用在IIS8中,因为为每一 ...
- 1034: [ZJOI2008]泡泡堂BNB - BZOJ
Description 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏泡泡堂.每一场比赛前,对阵 ...
- [JavaScript] js 判断闰年
/** * 判断闰年函数 * @param {number} year 要判断的年份 * @return {bool} 返回布尔值 * * 其实只要满足下面几个条件即可. * 1.普通年能被4整除且不 ...
- 论MOBA类游戏五号位的重要性
观众朋友们,也许你对题目很好奇,才打开这篇文章.为什么技术圈中会出现游戏类的软文?如果时间充足,可以继续往下看. MOBA 类游戏的兴起,逐渐吞噬游戏市场,以病毒式的扩张方式肆意改变着游戏玩家内心对游 ...
- 1989-C. 数字三角形
描述 如图所示,是一个数字搭成的三角形. 若起始位置在三角形的顶端,结束位置在三角形底边,每一步只能向下方或向右下角移动一格.请编程计算一条路径,使得路径上经过的数字和最大.(图中路径7→3→8→7→ ...