暴力能过,但这题本意应该不是让写暴力的,顺便学习一下状态压缩dp解法
暴力写法:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
char s[12];
int num[15];
int n,m;
signed main()
{
int T;
scanf("%lld",&T);
while(T--)
{
scanf("%s",s);n=strlen(s);
scanf("%lld",&m);
for(int i=0;i<n;i++)num[i]=s[i]-'0';
sort(num,num+n);
int res=0;
do
{
int t=0;
for(int i=0;i<n;i++)t=t*10+num[i];
if(t%m==0)res++;
}while(next_permutation(num,num+n));
printf("%lld\n",res);
}
}
状压dp写法
状态表示:
f[i][j]
表示:i表示要用到字符串中的哪一位,为1时即用到,0时不用,j指状态为j的余数
要用到同余定理,就是一个大数模除一个数的余数等于这个大数每一位的数模除这个数的结果。
状态转移方程:
f[(1<<k)|i][(j*10+a[k])%m]+=f[i][j];
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1100;
#define int long long
char s[12];
int num[12],a[12];
int f[N][N];
int n,m;
signed main()
{
int T;
scanf("%lld",&T);
while(T--)
{
memset(num,0,sizeof num);
memset(f,0,sizeof f);
scanf("%s%lld",s,&m);
int n=strlen(s);
for(int i=0;i<n;i++)num[s[i]-'0']++,a[i]=s[i]-'0';
f[0][0]=1;
for(int i=0;i<1<<n;i++)
{
for(int j=0;j<m;j++)
{
for(int k=0;k<n;k++)
{
if(i&(1<<k))continue;
f[(1<<k)|i][(j*10+a[k])%m]+=f[i][j];
}
}
}
int res=f[(1<<n)-1][0];
for(int i=0;i<=9;i++)
{
for(int j=1;j<=num[i];j++)
{
res/=j;
}
}
cout<<res<<endl;
}
}