题意:
一个数字,有些数位是?,要求你替换掉这些?,使得这个数字是N的倍数,没有前导0并且尽量小。
思路:
定义
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]代表选择了前i个数位,模N的余数为j,当前这一位选择了k是否可行。
因为我们要让这个数字最小,所以要从后往前遍历,这样回溯的时候就是从前往后,我们只要每次使用当前最小数字就可以保证这个数字最小了。
#include <cstdio>
#include <cstring>
#include<algorithm>
using namespace std;
const int maxn = 1005;
char s[maxn];
int dp[maxn][maxn][10];
int p[maxn];
int main() {
int n, mod;
scanf("%s%d", s+1, &mod);
n = strlen(s+1);
p[0] = 1;
for(int i = 1; i <= n; i++) {
p[i] = (p[i-1]*10)%mod;
}
memset(dp, -1, sizeof(dp));
dp[n+1][0][0] = 0;
for(int i = n; i >= 1; i--) {
for(int j = 0; j < mod; j++) {
for(int now = 0; now <= 9; now++) {
if(s[i] != '?' && now != s[i] - '0') continue;
for(int pre = 0; pre <= 9; pre++) {
if(dp[i+1][j][pre]!=-1) {
dp[i][(j+now*p[n-i])%mod][now] = dp[i+1][j][pre];
}
}
}
}
}
int flag = -1;
for(int i = 1; i <= 9; i++) {
if(dp[1][0][i]!=-1) {
flag = i;
break;
}
}
if(flag==-1) {
printf("*\n");
} else {
int sum = 0, now = flag;
for(int i = 1; i <= n; i++) {
printf("%d", now);
sum = ((sum-now*p[n-i])%mod+mod)%mod;
for(int j = 0; j <= 9; j++) {
if(dp[i+1][sum][j]!=-1) {
now = j;
break;
}
}
}
}
return 0;
}