【NOIP2018模擬賽2018.10.23】數
阿新 • • 發佈:2019-02-16
題目
數(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;
}