BZOJ传送门
洛谷传送门
解析:
水题状压。显然我们可以枚举状态 f s t a , k f_{sta,k} fsta,k表示当前选择了 s t a sta sta中的数, % d \%d %d的结果是 k k k的方案数。
考虑怎么避免重复,首先用排列去重是可以的,但是这明明是一道水题,有什么必要去推式子呢?
我们直接预处理出选择每一个数的前提状态,其实就是当序列中有多个 i i i的时候,保证选择第二个 i i i的时候第一个 i i i已经出现在状态里面了。
随便乱搞一发就能过。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
char s[10];
ll f[1<<11][1005];
int cnt[10];
int pre[10];
int d,len;
int T;
signed main(){
T=getint();
while(T--){
scanf("%s",s);
d=getint();len=strlen(s);
memset(f,0,sizeof f);
memset(cnt,0,sizeof cnt);
for(int re i=0;i<len;++i)s[i]^=48,++cnt[s[i]];
sort(s,s+len);
for(int re i=0;i<len;++i){
--cnt[s[i]];
if(cnt[s[i]])pre[i]=1<<(i+1);
else pre[i]=0;
}
f[0][0]=1;
for(int re i=0;i<(1<<len);++i){
for(int re j=0;j<len;++j){
if(((i&pre[j])==pre[j])&&!(i&(1<<j))){
for(int re k=0;k<d;++k)f[i|(1<<j)][(k*10+s[j])%d]+=f[i][k];
}
}
}
cout<<f[(1<<len)-1][0]<<"\n";
}
return 0;
}