【解题思路】

  状压DP。f[i][j][k]表示当前DP到第i位,模d意义下余数为j,状态为k的方案数。其中状态k表示每个数字还剩多少个没取,状态数最多210

  于是有递推式转移方程:f[i+1][(j+c)%d][k']+=f[i][j][k](c∈[0,9],k'为k删去数字c后的状态)。复杂度o(10T|s|d2|s|)。

【参考代码】

 1 #include <bits/stdc++.h>
 2 #define range(i,c,o) for(register int i=(c);i<(o);++i)
 3 #define dange(i,c,o) for(register int i=(c);i>(o);--i)
 4 using namespace std;
 5  
 6 //#define __debug
 7 #ifdef __debug
 8     #define Function(type) type
 9     #define Procedure      void
10 #else
11     #define Function(type) __attribute__((optimize("-O2"))) inline type
12     #define Procedure      __attribute__((optimize("-O2"))) inline void
13 #endif
14  
15 int cnt[10],tmp[10];
16 Function(int) status()
17 {
18     int ret=0;
19     range(i,0,10) (ret*=cnt[i]+1)+=tmp[i];
20     return ret;
21 }
22  
23 static int T,n,AwD; int f[10][1000][1024];
24 int DFS(const int&k,const int&r)
25 {
26     if(k==n) return !r; int S=status();
27     if(~f[k][r][S]) return f[k][r][S];
28     f[k][r][S]=0;
29     range(i,0,10) if(tmp[i])
30     {
31         --tmp[i];
32         f[k][r][S]+=DFS(k+1,(r*10+i)%AwD);
33         ++tmp[i];
34     }
35     return f[k][r][S];
36 }
37  
38 char s[15];
39 int main()
40 {
41     for(scanf("%d",&T);T--;)
42     {
43         scanf("%s%d",s,&AwD),n=strlen(s);
44         memset(cnt,0,sizeof cnt);
45         range(i,0,n) ++cnt[s[i]-'0'];
46         memcpy(tmp,cnt,sizeof tmp);
47         memset(f,-1,sizeof f);
48         printf("%d\n",DFS(0,0));
49     }
50     return 0;
51 }
View Code