此文说两种方法,对应紫书中的第二种与第三种
先说第三种方法
dp[i][j]表示的状态是:剩余 i 根火柴,当前拼成的数余数是j
dp[i][j]表示的值是:已经拼成的数的位数
具体来讲,其数的形式为 YXXX,其中XXX部分表示已经拼成的数,j是XXX对于m的余数,而i是用来拼除已拼好的X部分的剩余部分的火柴数量
d从大到小枚举下一位,来保证拼成的数最大
d枚举的实际上就是最高位,也就是Y那一位
这样dp[i][j]的更新可以解释:
dp[i][j]被dp[i-拼出d位需要的火柴数][(j*10+d)%m]更新,也就是被dp[剩余的火柴数][新的余数]更新
其中新的余数指的是YXXX对m的余数,旧的余数j是XXX对m的余数
提一提初始化情况和边界情况:
dp[i][0]=0,原因是,余数为0,剩余的火柴数不管有多少,这都是一个有效的状态,所以其对应的值应该被纳入考虑范围
dp[i][不是0]和p[i][j]都应该初始化为-1,表示没有有效值
无法解释的情况
在dp[n][0]可能表示的所有数中,不会出现00000....,即两个或两个以上0叠加来达到二位数或多位数,最多出现一位数的0,也就是0本身
如果你读到这里想到了什么办法说明,不会出现0000....的情况的原因,请随时告诉我
同时,我也会不断思考这个问题
其实还有一种情况,即数据较弱
代码在紫书代码仓库中
第二种方法
dp[i][j]表示拼了i位数,余数是j,dp[i][j]的值表示需要的火柴棒数量
因为每次下一位d枚举的是较高位,所以若位数相同都是最多的位数,且使用的火柴棒数量符合要求,此时非0的数会掩盖0成为最高位,原因见上红字
所以,请忽略00000..0形式的数,这样的数不会作为结果出现
边界处理 d[0][0]=0,因为如果d[0][非0]也等于0了,计算d[1][0]的时候,新增的数d不是m的倍数的情况也会被算成合法情况,实际上,其不合法,其余的d[][]全部赋值为不可能值,可以取大于n的数
在预处理计算形容1000,30000,9000等时,以及,输出答案时,需要用到两个模运算的性质
(n*10)%m=((n%m)*(10%m))%m
(a+b)%m=t 则
b%m=(t-a%m+m)%m
#include<iostream>
#include<cstdio>
using namespace std;
#define inf 105
const int maxn=105,maxm=3005;
int dp[maxn][maxm],r[maxn][10];
int n,m,kase;
int need[15]={6,2,5,5,4,5,6,3,7,6};
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
while(cin>>n>>m && n)
{
cout<<"Case "<<++kase<<": ";
//preprocess r array
for(int i=1;i<=9;i++) r[1][i]=i%m;
for(int i=2;i<=n;i++)
{
for(int d=1;d<=9;d++)
{
r[i][d]=(r[i-1][d]*(10%m))%m;
}
}
/*
for(int i=0;i<=n;i++){
for(int j=1;j<=9;j++)
printf("r[%d][%d]=%d\n",i,j,r[i][j]);
}
*/
//initialize dp array
for(int i=0;i<=n;i++) {
for(int j=0;j<m;j++) dp[i][j]=inf;
}
dp[0][0]=0;
for(int i=0;i<=n;i++){
for(int j=0;j<m;j++){
for(int d=9;d>=0;d--){
int &ans=dp[i+1][(j*10+d)%m];
ans=min(ans,dp[i][j]+need[d]);
}
}
}
/*
for(int i=0;i<=n;i++){
for(int j=0;j<m;j++){
printf("dp[%d][%d]=%d\n",i,j,dp[i][j]);
}
}
*/
int i;
for(i=n;i>0;i--) if(dp[i][0]<=n) break;
if(i==0) cout<<-1<<"\n";
else{
int t=0;
for(;i>=1;i--){
int d;
for(d=9;d>=0;d--)
{
int nxt=(t-r[i][d]+m)%m;
if(dp[i-1][nxt]+need[d]<=n)
{
n-=need[d];
t=nxt;
break;
}
}
cout<<d;
}
cout<<"\n";
}
}
return 0;
}
836






