【解题思路】
状压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 }
We Secure, We Contain, We Protect.