Luogu 4163
题目分析:
-
这个题要求的排列是不能重复的,所有我们先假定 s s s的每位数不相等,最后统计答案数去掉重复的就 O K OK OK
-
考虑枚举排列的过程:
有一个 s 串 : a b c s串:abc s串:abc,我们已经排列到了 b a , 此 时 的 余 数 为 j ba,此时的余数为j ba,此时的余数为j
当我们把 c c c加进来时,变成了 b a c bac bac,相当于就是 b a ∗ 10 + c ba*10+c ba∗10+c
而余数又会怎么变化呢?
j 变 成 了 ( j ∗ 10 + c ) j变成了(j*10+c) j变成了(j∗10+c)% d d d -
我们定义 f [ i ] [ j ] 表 示 状 态 为 i ( i 的 每 一 位 表 示 s 串 中 的 数 字 选 或 不 选 ) 时 f[i][j]表示状态为i(i的每一位表示s串中的数字选或不选)时 f[i][j]表示状态为i(i的每一位表示s串中的数字选或不选)时, 余 数 为 j 的 方 案 数 余数为j的方案数 余数为j的方案数
-
边界 f [ i ] [ j ] = 0 , f [ 0 ] [ 0 ] = 1 f[i][j]=0,f[0][0]=1 f[i][j]=0,f[0][0]=1
-
状态转移:
f [ i U x ] [ ( j ∗ 10 + a [ x ] ) f[iUx][(j*10+a[x]) f[iUx][(j∗10+a[x])% d ] + = f [ i ] [ j ] d]+=f[i][j] d]+=f[i][j]
Code:
#include <bits/stdc++.h>
using namespace std;
#define maxd 1010
#define maxn 20
#define max_size 1100
int a[maxn],T,d,n,f[max_size][maxd],cnt[maxn];
char s[maxn];
inline int read_() {
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*f;
}
inline void clean_() {
memset(f,0,sizeof(f));
memset(cnt,0,sizeof(cnt));
}
inline void DP_() {
f[0][0]=1;
for(int i=0;i<(1<<n);++i) {
for(int j=0;j<d;++j) {
for(int k=1;k<=n;++k) {
if( ! ( i & (1<<(k-1)) ) ) {
f[i|(1<<(k-1))][(j*10+a[k])%d]+=f[i][j];
}
}
}
}
int ans=f[(1<<n)-1][0];
for(int i=0;i<=9;++i) {
for(int j=2;j<=cnt[i];++j) {
ans/=j;
}
}
printf("%d\n",ans);
}
void readda_() {
T=read_();
while(T--) {
clean_();
scanf("%s",s);
d=read_();
n=strlen(s);
for(int i=0;i<n;++i) {
a[i+1]=s[i]-'0';
++cnt[a[i+1]];
}
DP_();
}
}
int main() {
freopen("a.txt","r",stdin);
readda_();
return 0;
}