咱們用w[i][j]來表示,i是一個二進制表示咱們選取了s中的某些位,j表示這些位%d爲j,w[i][j]則表示這樣狀況下的方案數,那麼咱們能夠獲得轉移.w[i|(1<<k)][(j*10+s[k]-'0')%d]+=w[i][j]。spa
假設s中有x個3,那麼咱們算出的狀態中一樣的數咱們算了x!次,最後除掉就行了。code
/************************************************************** Problem: 1072 User: BLADEVIL Language: C++ Result: Accepted Time:476 ms Memory:12680 kb ****************************************************************/ //By BLADEVIL #include <cstdio> #include <cstring> using namespace std; int d,cnt[11],w[3010][1010]; char s[11]; int main() { int task; scanf("%d",&task); while (task--) { scanf("%s%d",s,&d); int len=strlen(s); memset(cnt,0,sizeof cnt); for (int i=0;i<len;i++) cnt[s[i]-'0']++; for (int i=0;i<(1<<len);i++) for (int j=0;j<d;j++) w[i][j]=0; w[0][0]=1; for (int i=0;i<(1<<len);i++) for (int j=0;j<d;j++) if (w[i][j]) for (int k=0;k<len;k++) if (!(i&(1<<k))) w[i|(1<<k)][(j*10+s[k]-'0')%d]+=w[i][j]; int ans=w[(1<<len)-1][0]; //printf("%d\n",ans); for (int i=0;i<10;i++) for (int j=1;j<=cnt[i];j++) { ans/=j ; } printf("%d\n",ans); } return 0; }