Bzoj1072 [SCOI2007]排列perm
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
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29
Sample Output
1
3
3628800
90
3
6
1398
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 }
本文为博主原创文章,转载请注明出处。