【NOIP提高A组模拟2018.8.18】 number

本文介绍了一种使用数位动态规划(DP)解决特定数学问题的方法,该问题要求找出满足特定条件的正整数数量。这些条件包括:数字为给定数n的重排列、是给定数m的倍数且不含前导零。文章通过实例解释了如何通过状态压缩和枚举技术来实现这一目标,并提供了一个完整的C++代码示例。

【题目描述】

给定正整数 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。

状压记录 0 到 9 剩余个数以及 mod m 的值的情况下的方 案数。转移时枚举最高位填的数字,最后一次转移不要枚 举 0。

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
long long c[12],b[12],dp[65535][117],w[12];
int a[12],m;
string s;
int main(){
    cin>>s>>m;
    int len=s.size();
    for(int i=0; i<len; i++) a[s[i]-'0']++;
    c[0]=1;
	b[0]=c[0]*a[0];
    for (int i=1; i<=9; i++){
		c[i]=b[i-1]+1;b[i]=b[i-1]+c[i]*a[i];
    } 
    for(int i=1; i<=9; i++)
		if (a[i]>0) dp[c[i]][i%m]=1;
    for (int i=1; i<=b[9]; i++){
		int x=i;
        for(int j=9; j>=0; j--) w[j]=a[j]-(x/c[j]),x%=c[j];
        for(int j=0; j<=9; j++) 
			if(w[j]>0)for(int k=0;k<=m-1;k++){
				dp[i+c[j]][(k*10+j)%m]+=dp[i][k]+mod;
				dp[i+c[j]][(k*10+j)%m]%=mod;
			} 
    }
    cout<<dp[b[9]][0]<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值