题目
数(number)
题目描述】
给定正整数n,m,问有多少个正整数满足:
(1)不含前导0;
(2)是m的倍数;
(3)可以通过重排列各个数位得到n。
【输入数据】
一行两个整数n,m。
【输出数据】
一行一个整数表示答案对998244353取模的结果。
【样例输入】
1 1
【样例输出】
1
【数据范围】
对于20%的数据,n<10^10。
对于50%的数据,n<10^16,m<=20。
对于100%的数据,n<10^20,m<=100。
题解
–是一道简单的状压数位dp
f[i][j]:表示当前选数状态是i,模m为j的方案数
当然这道题要用变进制数来压
要好好理解一下
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=25;
const int mod=998244353;
char n;
int a[10],b[10],m,l;
int k[10],p[10];
long long f[100005][105];
int main(){
// freopen("number.in","r",stdin);
// freopen("number.out","w",stdout);
while(n=getchar()){
if(n<'0'||n>'9')
break;
a[n-'0']++;
}
cin>>m;
for(int i=0;i<=9;i++)
if(a[i])
b[++l]=i;
if(l==1&&!b[l]){
cout<<1;
return 0;
}
k[0]=1;
for(int i=1;i<=l;i++){
k[i]=k[i-1]*(a[b[i]]+1);
p[i]=k[i-1];
}
f[0][0]=1;
for(int i=1;i<k[l];i++){
int now=i;
for(int j=l;j>=1;j--){
if(now>=p[j]){
if(!b[j]&&i<=k[j])
continue;
for(int x=0;x<m;x++)
f[i][(x*10+b[j])%m]=(f[i][(x*10+b[j])%m]+f[i-p[j]][x])%mod;
now%=p[j];
}
}
}
cout<<f[k[l]-1][0];
return 0;
}