您的位置:首页 > 其它

【以前的空间】bzoj 1072 [SCOI2007]排列perm

2017-03-02 19:02 323 查看
又颓废了一个下午,最近撸mc撸到丧失意识了,玩的有点恶心,于是找水题做,瞧不起颓废的自己啊。

another水题。

这题题意很明显啦,就是找数字排列后组成的数去mod d=0后有多少种。

普通的搜索的话,是会tle的(应该是o(n!)没错?)。注意到长度n还是比较小的,于是想到状压dp。

状态就是每个数取和不取组成的结果(就是00110表示第3,4个数取了啦,学过状压都知道)。

然后转移就是f[i,j,k]表示现在取到第i个数状态为i余数为j有多少种情况,

那么f[i,j,(k*10+a[i])mod d]=Σf[i-1,j',k](也就是同余的东西啦,在123后加一个数字4,那么1234 mod d=((123 mod d *10)+4 )mod d )。k的范围就是0-(d-1)啦。其实就是一个01背包,然后i是可以去掉的。

最后就是处理重复的问题了,之前好像也做过类似的,不过反过来的……重复的话可以这么想,比如有4个2重复,那么对于第4个2来说,加上它后重复的情况就是之前的情况*4,对于第三个2来说,加上它后重复的情况就是之前的情况*3,对于第二个2就是之前的情况*2(其实就是个排列组合……四个2有序号要比没有序号多A(4,4)=4!)。

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
var
b:array[0..10,0..2000]of longint;
c,a:array[0..20]of longint;
f:array[0..2000,0..1500]of longint;
i,j,k,l,n,m,t,tot,top:longint;

procedure into;
var
i,j,k,len:longint;
s:string;
begin
readln(s);
len:=length(s);
i:=pos(' ',s);
val(copy(s,i+1,len-i),tot);
delete(s,i,len-i+1);
n:=length(s);
fillchar(c,sizeof(c),0);
for i:=1 to n do begin
a[i]:=ord(s[i])-ord('0');
inc(c[a[i]]);
end;
top:=1<<n-1;
fillchar(b,sizeof(b),0);
for i:=0 to top do begin
j:=i;
k:=0;
while j<>0 do begin
inc(k);
dec(j,j and (-j));
end;
j:=k;
inc(b[j,0]);
b[j,b[j,0]]:=i;
end;
end;

procedure work;
var
i,j,k,l,m,ans:longint;
begin
fillchar(f,sizeof(f),0);
for i:=1 to n do
f[1<<(i-1),a[i] mod tot]:=1;
for i:=2 to n do
for j:=1 to b[i,0] do begin
k:=b[i,j];
for l:=1 to n do
if k and (1<<(l-1)) <> 0 then
for m:=0 to tot-1 do
inc(f[k,(10*m+a[l]) mod tot],f[k-1<<(l-1),m]);
end;
ans:=f[top,0];
for i:=0 to 9 do
if c[i]>1 then
for j:=2 to c[i] do ans:=ans div j;
writeln(ans);
end;

begin
readln(t);
while t>0 do begin
dec(t);
into;
work;
end;
end.


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: