Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #define MAXN 101
- #define MAXM 3001
- // 每个数字0-9所需的火柴数
- static int cost[10] = {6,2,5,5,4,5,6,3,7,6};
- // 我们用字符串存储最大数,为方便比较和拼接,采用字典序比较。
- // dp[i][r] 存储使用i根火柴、余数为r时的最大数串。
- // 若无解则存NULL。为简化存储和比较,可使用char*数组进行动态管理。
- static char *dp[MAXN][MAXM];
- int main() {
- int T;
- scanf("%d", &T);
- while(T--) {
- int n, m;
- scanf("%d %d", &n, &m);
- // 初始化dp数组
- for (int i = 0; i <= n; i++) {
- for (int r = 0; r < m; r++) {
- dp[i][r] = NULL;
- }
- }
- // 初始状态:使用0根火柴,余数为0,可以看作空字符串
- // 空字符串表示还没选数字,不是最终答案,但作为起点
- dp[0][0] = strdup("");
- // 开始DP
- for (int i = 0; i <= n; i++) {
- for (int r = 0; r < m; r++) {
- if (dp[i][r] == NULL) continue; // 无解跳过
- // 当前已有的字符串
- char *current = dp[i][r];
- // 尝试添加数字d
- for (int d = 0; d <= 9; d++) {
- int c = cost[d];
- if (i + c <= n) {
- // 判断前导0问题
- // 若当前dp[i][r]是空字符串,则添加的第一个数字不能为0(除非最终数字就是0,但题意需正整数)
- if (strlen(current) == 0 && d == 0) continue;
- int new_r = (r * 10 + d) % m;
- // 构造新字符串
- // 新的数字应当加在后面,因为我们一直在往后拼数字
- int len_cur = (int)strlen(current);
- char *new_str = (char*)malloc(len_cur + 2);
- strcpy(new_str, current);
- new_str[len_cur] = (char)('0' + d);
- new_str[len_cur + 1] = '\0';
- // 更新dp[i+c][new_r]
- // 比较字典序(长度相同比较字典序,长度大的数串代表更大的数字,因为没有前导0)
- if (dp[i+c][new_r] == NULL) {
- dp[i+c][new_r] = new_str;
- } else {
- // 比较大小,长度长的更大;长度相同则字典序大的更大
- int len_old = (int)strlen(dp[i+c][new_r]);
- int len_new = (int)strlen(new_str);
- if (len_new > len_old) {
- free(dp[i+c][new_r]);
- dp[i+c][new_r] = new_str;
- } else if (len_new == len_old && strcmp(new_str, dp[i+c][new_r]) > 0) {
- free(dp[i+c][new_r]);
- dp[i+c][new_r] = new_str;
- } else {
- free(new_str); // 新的方案不更优,丢弃
- }
- }
- }
- }
- }
- }
- // 寻找满足余数为0的最大数字
- char *ans = NULL;
- for (int i = 1; i <= n; i++) {
- if (dp[i][0] != NULL) {
- // dp[i][0]是可能的答案
- // 需要ans中存放最大值
- if (ans == NULL) {
- ans = dp[i][0];
- } else {
- int len_a = (int)strlen(ans);
- int len_b = (int)strlen(dp[i][0]);
- if (len_b > len_a) {
- free(ans);
- ans = dp[i][0];
- } else if (len_a == len_b && strcmp(dp[i][0], ans) > 0) {
- free(ans);
- ans = dp[i][0];
- } else {
- // dp[i][0]不更好,需要释放
- free(dp[i][0]);
- }
- }
- }
- }
- // ans中存放最大的可行数,若ans仍为空,则无解
- if (ans == NULL) {
- printf("-1\n");
- } else {
- // 注意这里ans有可能是"0"吗?理论上,如果m=1,n=6,可以用"0"吗?
- // 我们筛选时,第一个数字不能为0(除非是后续追加,但那样数字不会只有0)。
- // 因此若存在ans,必为正整数。
- printf("%s\n", ans);
- free(ans);
- }
- // 清理未使用的dp内存
- // 因为我们逐个申请了内存,但释放只在用到结果时释放。
- // 剩下的未用的dp[i][r]在下个用例前要释放。
- // 为避免重复释放,建议在使用结束后循环清理。
- for (int i = 0; i <= n; i++) {
- for (int r = 0; r < m; r++) {
- // 有的指针可能已被转移到ans或者已被释放,检查NULL即可
- if (dp[i][r] != NULL) {
- // 如果dp[i][r]不是ans,则释放
- // 不过上面我们在选择最大答案时,会free掉不匹配的dp[i][0],也会free ans
- // 这里为了安全起见,统一清理所有dp[i][r],这里的释放只会对剩下的未参与ans的内容产生影响。
- free(dp[i][r]);
- dp[i][r] = NULL;
- }
- }
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement