Advertisement
Guest User

Untitled

a guest
Dec 14th, 2024
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.65 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5.  
  6. #define MAXN 101
  7. #define MAXM 3001
  8.  
  9. // 每个数字0-9所需的火柴数
  10. static int cost[10] = {6,2,5,5,4,5,6,3,7,6};
  11.  
  12. // 我们用字符串存储最大数,为方便比较和拼接,采用字典序比较。
  13. // dp[i][r] 存储使用i根火柴、余数为r时的最大数串。
  14. // 若无解则存NULL。为简化存储和比较,可使用char*数组进行动态管理。
  15. static char *dp[MAXN][MAXM];
  16.  
  17. int main() {
  18.     int T;
  19.     scanf("%d", &T);
  20.     while(T--) {
  21.         int n, m;
  22.         scanf("%d %d", &n, &m);
  23.  
  24.         // 初始化dp数组
  25.         for (int i = 0; i <= n; i++) {
  26.             for (int r = 0; r < m; r++) {
  27.                 dp[i][r] = NULL;
  28.             }
  29.         }
  30.  
  31.         // 初始状态:使用0根火柴,余数为0,可以看作空字符串
  32.         // 空字符串表示还没选数字,不是最终答案,但作为起点
  33.         dp[0][0] = strdup("");
  34.  
  35.         // 开始DP
  36.         for (int i = 0; i <= n; i++) {
  37.             for (int r = 0; r < m; r++) {
  38.                 if (dp[i][r] == NULL) continue; // 无解跳过
  39.                 // 当前已有的字符串
  40.                 char *current = dp[i][r];
  41.                 // 尝试添加数字d
  42.                 for (int d = 0; d <= 9; d++) {
  43.                     int c = cost[d];
  44.                     if (i + c <= n) {
  45.                         // 判断前导0问题
  46.                         // 若当前dp[i][r]是空字符串,则添加的第一个数字不能为0(除非最终数字就是0,但题意需正整数)
  47.                         if (strlen(current) == 0 && d == 0) continue;
  48.  
  49.                         int new_r = (r * 10 + d) % m;
  50.  
  51.                         // 构造新字符串
  52.                         // 新的数字应当加在后面,因为我们一直在往后拼数字
  53.                         int len_cur = (int)strlen(current);
  54.                         char *new_str = (char*)malloc(len_cur + 2);
  55.                         strcpy(new_str, current);
  56.                         new_str[len_cur] = (char)('0' + d);
  57.                         new_str[len_cur + 1] = '\0';
  58.  
  59.                         // 更新dp[i+c][new_r]
  60.                         // 比较字典序(长度相同比较字典序,长度大的数串代表更大的数字,因为没有前导0)
  61.                         if (dp[i+c][new_r] == NULL) {
  62.                             dp[i+c][new_r] = new_str;
  63.                         } else {
  64.                             // 比较大小,长度长的更大;长度相同则字典序大的更大
  65.                             int len_old = (int)strlen(dp[i+c][new_r]);
  66.                             int len_new = (int)strlen(new_str);
  67.                             if (len_new > len_old) {
  68.                                 free(dp[i+c][new_r]);
  69.                                 dp[i+c][new_r] = new_str;
  70.                             } else if (len_new == len_old && strcmp(new_str, dp[i+c][new_r]) > 0) {
  71.                                 free(dp[i+c][new_r]);
  72.                                 dp[i+c][new_r] = new_str;
  73.                             } else {
  74.                                 free(new_str); // 新的方案不更优,丢弃
  75.                             }
  76.                         }
  77.                     }
  78.                 }
  79.             }
  80.         }
  81.  
  82.         // 寻找满足余数为0的最大数字
  83.         char *ans = NULL;
  84.         for (int i = 1; i <= n; i++) {
  85.             if (dp[i][0] != NULL) {
  86.                 // dp[i][0]是可能的答案
  87.                 // 需要ans中存放最大值
  88.                 if (ans == NULL) {
  89.                     ans = dp[i][0];
  90.                 } else {
  91.                     int len_a = (int)strlen(ans);
  92.                     int len_b = (int)strlen(dp[i][0]);
  93.                     if (len_b > len_a) {
  94.                         free(ans);
  95.                         ans = dp[i][0];
  96.                     } else if (len_a == len_b && strcmp(dp[i][0], ans) > 0) {
  97.                         free(ans);
  98.                         ans = dp[i][0];
  99.                     } else {
  100.                         // dp[i][0]不更好,需要释放
  101.                         free(dp[i][0]);
  102.                     }
  103.                 }
  104.             }
  105.         }
  106.  
  107.         // ans中存放最大的可行数,若ans仍为空,则无解
  108.         if (ans == NULL) {
  109.             printf("-1\n");
  110.         } else {
  111.             // 注意这里ans有可能是"0"吗?理论上,如果m=1,n=6,可以用"0"吗?
  112.             // 我们筛选时,第一个数字不能为0(除非是后续追加,但那样数字不会只有0)。
  113.             // 因此若存在ans,必为正整数。
  114.             printf("%s\n", ans);
  115.             free(ans);
  116.         }
  117.  
  118.         // 清理未使用的dp内存
  119.         // 因为我们逐个申请了内存,但释放只在用到结果时释放。
  120.         // 剩下的未用的dp[i][r]在下个用例前要释放。
  121.         // 为避免重复释放,建议在使用结束后循环清理。
  122.         for (int i = 0; i <= n; i++) {
  123.             for (int r = 0; r < m; r++) {
  124.                 // 有的指针可能已被转移到ans或者已被释放,检查NULL即可
  125.                 if (dp[i][r] != NULL) {
  126.                     // 如果dp[i][r]不是ans,则释放
  127.                     // 不过上面我们在选择最大答案时,会free掉不匹配的dp[i][0],也会free ans
  128.                     // 这里为了安全起见,统一清理所有dp[i][r],这里的释放只会对剩下的未参与ans的内容产生影响。
  129.                     free(dp[i][r]);
  130.                     dp[i][r] = NULL;
  131.                 }
  132.             }
  133.         }
  134.  
  135.     }
  136.     return 0;
  137. }
  138.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement