题意:你的任务是用不超过n根火柴摆一个尽量大的,能被m整除的正整数,无解时输出-1
思路:先预处理出用不超过n根火柴能摆成的最大数有几位,那么只有当这个数是m的倍数,它的位数越大才有用,那么用一维记录余数,所以dp[i][j]表示用i根组成的数余数是j的最大位数是多少,接下来的就是打印各个位上的数了,试想一下满足的条件,
dp[i][j]+1==dp[newi][newj]满足的话,那么如果dp[newi][newj]存在的话,那么新增的K就是下一位,用next[i][j]表示当前状态的下一个数
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 110;
const int MAXM = 3010;
const int used[10] = {6,2,5,5,4,5,6,3,7,6};
int dp[MAXN][MAXM],next[MAXN][MAXM];
int n,m,maxlen;
int main(){
int cas = 0;
while (scanf("%d",&n) != EOF && n){
scanf("%d",&m);
memset(dp,-1,sizeof(dp));
dp[0][0] = 0,maxlen = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (dp[i][j] >= 0)
for (int k = 9; k >= 0; k--)
if (i + used[k] <= n){
int newi = i+used[k],newj = (j*10+k)%m;
if (dp[i][j] + 1 > dp[newi][newj]){
dp[newi][newj] = dp[i][j] + 1;
if (dp[newi][newj] > maxlen && newj == 0)
maxlen = dp[newi][newj];
}
}
memset(next,-1,sizeof(next));
for (int i = n; i >= 0; i--)
for (int j = 0; j < m; j++)
if (dp[i][j] >= 0){
if (dp[i][j] == maxlen && j == 0){
next[i][j] = 10;
continue;
}
for (int k = 9; k >= 0; k--){
if (i + used[k] <= n){
int newi = i + used[k];
int newj = (j*10+k)%m;
if (dp[newi][newj] == dp[i][j] + 1 && next[newi][newj] >= 0){
next[i][j] = k;
break;
}
}
}
}
printf("Case %d: ",++cas);
int i,j,u,v;
if (maxlen > 0){
i = 0,j = 0;
while (next[i][j] != 10){
u = i + used[next[i][j]];
v = (j*10+next[i][j]) % m;
printf("%d",next[i][j]);
i = u,j = v;
}
printf("\n");
}
else if (n >= used[0])
printf("0\n");
else printf("-1\n");
}
return 0;
}