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

又颓废了一个下午,最近撸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.

时间: 2024-08-09 22:02:50

【以前的空间】bzoj 1072 [SCOI2007]排列perm的相关文章

[BZOJ 1072] [SCOI2007] 排列perm 【状压DP】

题目链接:BZOJ 1072 这道题使用 C++ STL 的 next_permutation() 函数直接暴力就可以AC .(使用 Set 判断是否重复) 代码如下: #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <set>

BZOJ 1072 [SCOI2007]排列perm

考虑到s的长度特别小,只有10,可以考虑状压dp. 设F[S][d]表示当选了集合S(用二进制压位表示)中的所有位置,对D取模的结果为d的方案总数:不难想到转移和初始化. 初始化:F[0][0]=1  0在这里表示空集合 转移:F[S][(d * 10 + s[i]-'0') % D]=sum{F[S0][d]}  S0是S的一个子集,并且刚好只比S少一个元素i 注意,重复的数字被算了多遍.样例当中就有.因此最后的答案要除以所有重复的数字个数的阶乘. 看代码就明白啦~ (再补充一个要用到状压技巧

BZOJ 1072: [SCOI2007]排列perm [DP 状压 排列组合]

题意:给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0) 100%的数据满足:s的长度不超过10, 1<=d<=1000, 1<=T<=15 看到整除应该往余数方面想 $f[s][i]$表示当前已经选择的数的集合为$s$,余数为$i$的方案数 枚举下一个数字,用更新的写法转移 注意是有重复元素的排列!除上个阶乘 #include <iostream> #include <cstdio> #include <cstring&g

BZOJ 1072 SCOI2007 排列perm 状压DP

题目大意:给定n个数字,求这些数字的全排列中有多少数能被d整除 令f[i][j]为状态为i,余数为j的方案数 枚举最高位转移 小心爆int #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,d,ans,f[1<<10][1<<10],digit[1<<10],tens[10

【BZOJ】1072: [SCOI2007]排列perm(状压dp+特殊的技巧)

http://www.lydsy.com/JudgeOnline/problem.php?id=1072 首先无限膜拜题解orz表示只会暴力orz 数据那么小我竟然想不到状压! orz 这种题可以取模设状态orz f[i,j]表示状态为i,mod d为j的方案 则答案为f[all, 0] 转移就太简单了orz f[i|1<<k, (j*10+c[k])%d]+=f[i, j] 然后我有一sb错一直没找到,wa了n发... QAQ #include <cstdio> #include

1072: [SCOI2007]排列perm

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3000  Solved: 1875[Submit][Status][Discuss] Description 给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0).例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种. Input 输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开.s保证只包含数字0, 1, 2,

【BZOJ 1072】 [SCOI2007]排列perm

1072: [SCOI2007]排列perm Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 998  Solved: 612 [Submit][Status] Description 给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0).例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种. Input 输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开.s保证

[BZOJ1072][SCOI2007]排列perm 状压dp

1072: [SCOI2007]排列perm Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2488  Solved: 1546[Submit][Status][Discuss] Description 给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0).例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种. Input 输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间

SCOI2007排列perm

1072: [SCOI2007]排列perm Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 805  Solved: 497[Submit][Status] Description 给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0).例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种. Input 输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开.s保证只包