Bzoj1072 [SCOI2007]排列perm

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2086  Solved: 1302
[Submit][Status][Discuss]

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的倍数。

【限制】

100%的数据满足:s的长度不超过10, 1<=d<=1000, 1<=T<=15

 

动规 状压DP

f[状态][余数]=方案数

由于不同顺序选择出的同一数被当成同一方案,所以最后要除法去重

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #define LL long long
 8 using namespace std;
 9 const int mxn=1010;
10 int T;
11 LL f[1<<11][mxn];
12 int b[20],p[20];
13 char s[20];int d;
14 int w[20];
15 int main(){
16     int i,j,k;
17     for(i=0;i<15;i++)b[i]=1<<i;
18     p[0]=1;
19     for(i=1;i<12;i++)p[i]=i*p[i-1];
20     scanf("%d",&T);
21     while(T--){
22         memset(f,0,sizeof f);
23         memset(w,0,sizeof w);
24         scanf("%s%d",s,&d);
25         int n=strlen(s);
26         for(i=0;i<n;i++)w[s[i]-'0']++;
27         f[0][0]=1;
28         int ed=(1<<n)-1;
29         for(i=0;i<=ed;i++){
30             for(j=0;j<n;j++){
31                 if(i&b[j])continue;
32                 for(k=0;k<d;k++){
33                     f[i|b[j]][(k*10+s[j]-'0')%d]+=f[i][k];
34                 }
35             }
36         }
37         for(i=0;i<=9;i++)if(w[i])f[ed][0]/=p[w[i]];
38         printf("%lld\n",f[ed][0]);
39     }
40     return 0;   
41 }

 

posted @ 2017-02-24 12:09  SilverNebula  阅读(188)  评论(0编辑  收藏  举报
AmazingCounters.com