1. 程式人生 > >【NOIP2018模擬賽2018.10.23】數

【NOIP2018模擬賽2018.10.23】數

題目

數(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; }