题意:给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0)。例如123434有90种排列能
被2整除,其中末位为2的有30种,末位为4的有60种。
一开始看见s小于10秒想状压,然后在dp式子卡了一下才想到。。
设f[i][j]表示使用了多少位的状态,余数为j的方案数。
那么明显有
f[i|(1<<k)][(j∗10+a[k])
但是这样肯定会算重,然后我就萎了。。其实很简单,就是/每个数出现的次数的阶乘就好了。。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=2e3+5;
int f[N][N],a[N],cnt[N];
int ans,n,m;
char ch[20];
int main()
{
int cas;
scanf("%d",&cas);
while (cas--)
{
scanf("%s%d",ch,&n);
m=strlen(ch);
memset(cnt,0,sizeof(cnt));
memset(f,0,sizeof(f));
fo(i,0,m-1)
{
a[i]=ch[i]-'0';
++cnt[a[i]];
}
f[0][0]=1;
int tot=1<<m;
fo(i,0,tot-1)
{
fo(j,0,n-1)
{
fo(k,0,m-1)
{
if ((i&(1<<k))==0)
f[i|(1<<k)][(j*10+a[k])%n]+=f[i][j];
}
}
}ans=f[tot-1][0];
fo(i,0,9)
{
fo(j,1,cnt[i])ans/=j;
}
printf("%d\n",ans);
}
}