SCOI2007排列perm

1072: [SCOI2007]排列perm

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 805  Solved: 497
[Submit][Status]

Description

给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0)。例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种。

Input

输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开。s保证只包含数字0, 1, 2, 3, 4, 5, 6, 7, 8, 9.

Output

每个数据仅一行,表示能被d整除的排列的个数。

Sample Input

7
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29

Sample Output

1
3
3628800
90
3
6
1398

HINT

在前三个例子中,排列分别有1, 3, 3628800种,它们都是1的倍数。 【限制】 20%的数据满足:s的长度不超过5, 1<=T<=5 50%的数据满足:s的长度不超过8 100%的数据满足:s的长度不超过10, 1<=d<=1000, 1<=T<=15,

Source

题解:

又一道恶心的状压DP,我对状压还不熟悉。。。

代码:

 1 var f:array[0..10,0..1025,0..1025] of longint;
 2     i,j,nn,k,m,t,l,ans,d,n:longint;
 3     s,st:ansistring;
 4     a,calc,c:array[0..1025] of longint;
 5     b:array[0..10,0..1025] of longint;
 6 procedure init;
 7  begin
 8    readln(s);
 9    st:=copy(s,1,pos(‘ ‘,s)-1);
10    n:=length(st);
11    for i:=1 to n do a[i]:=ord(st[i])-ord(‘0‘);
12    delete(s,1,pos(‘ ‘,s));
13    val(s,d);//writeln(st,‘ ‘,d);
14    fillchar(b,sizeof(b),0);
15    for i:=0 to 1<<n-1 do
16      begin
17       j:=i;calc[i]:=0;
18       while j<>0 do
19        begin
20         inc(calc[i]);dec(j,j and (-j));
21        end;
22       j:=calc[i];
23       inc(b[j,0]);b[j,b[j,0]]:=i;
24      end;
25  end;
26 procedure main;
27  begin
28    fillchar(f,sizeof(f),0);
29    for i:=1 to n do f[1,1<<(i-1),a[i] mod d]:=1;
30    for i:=2 to n do
31     for l:=1 to b[i,0] do
32      begin
33       j:=b[i,l];
34       for k:=1 to n do
35        if j and (1<<(k-1))<>0 then
36         for m:=0 to d-1 do
37          inc(f[i,j,(10*m+a[k]) mod d],f[i-1,j-1<<(k-1),m]);
38      end;
39    ans:=f[n,1<<n-1,0];
40    fillchar(c,sizeof(c),0);
41    for i:=1 to n do inc(c[a[i]]);
42    for i:=0 to 9 do
43      if c[i]<=1 then continue
44      else for j:=2 to c[i] do ans:=ans div j;
45    writeln(ans);
46  end;
47
48 begin
49   assign(input,‘input.txt‘);assign(output,‘output.txt‘);
50   reset(input);rewrite(output);
51   readln(t);
52   while t>0 do
53    begin
54     dec(t);
55     init;
56     main;
57    end;
58   close(input);close(output);
59 end.  

SCOI2007排列perm

时间: 2024-12-12 17:25:13

SCOI2007排列perm的相关文章

[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,中间

【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

给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0) s的长度<=10    d<=1000  数据组数<=15 非常奇妙的一道题,题目的样例居然还告诉了你总共最多有多少种排列...... 算了算...10!*15 才5000多万,貌似可以暴力!! 于是就写了一个按数字串的每一位搜索的暴力上去,T了..... 然后考虑了一下,发现同一位没必要搜相同数字啊....然后就改成了搜一位放什么数字.... 然后瞬间就过了. 复杂度最大应该就是10!*15=5443200

[bzoj1072][SCOI2007][排列perm] (状态压缩+数位dp+排列去重)

Description 给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0).例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种. Input 输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开.s保证只包含数字0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Output 每个数据仅一行,表示能被d整除的排列的个数. Sample Input 7 000 1 001 1 1234567890 1 1

【枚举】bzoj1072 [SCOI2007]排列perm

暴力,next_permutation函数用于枚举出下一个排列.sscanf函数用于将字符串转化成数字. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int n,len,ans; 6 long long x,t; 7 char s[15]; 8 int main() 9 { 10 scanf("%d",&n); 11

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

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

【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

[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>