1. 程式人生 > >Gym101889E. Enigma(bfs+數位)

Gym101889E. Enigma(bfs+數位)

比賽連結:傳送門

題目大意:

  求一個十進位制大數S(有部分數位為"?")能被N整除時的最小值,如果沒有辦法被N整除,輸出"*"。

思路:

  一個數位上的數值增加1後,對N取模時的貢獻可以預處理出來。設為mod[MAX_N]。

  先把整個十進位制大數置成最小的合法狀態,存在res中。(問號置為0或1)

  此時的大數對N取模的值是可以計算的。設為val。

  如果val為0,res中已經是最大的答案。

  如果val不為0,從最右邊的"?"開始往左列舉"?"。

  維護一個vis陣列,vis[k] = true表示已經訪問過的問號當中,至少有一種填法使得整個大數對N取模的餘數為k。

  如果vis[N-val] = true,說明找到了一種填法。因為是從右往左列舉"?"的,第一次得到vis[N-val] = true時,幾乎就是最小的了。考慮到當前數位填的數相同時,可能在當前的"?"右邊的"?"填數不同,可能導致最小值不同,所以要額外judge一下。更新vis陣列時,記錄路徑,在vis[N-val] = true時,反演路徑,對應修改res中對應數位的數值即可。

程式碼:

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1000 + 5;
const int
INF = 0x3f3f3f3f; int N;//取模 int len;//S的長度 char S[MAX_N], res[MAX_N]; int mod[MAX_N];//數位取模的值 int val;//work構造模N為val的值 bool vis[MAX_N], tmpvis[MAX_N];//vis[i]能否構造模N為i的值 int fat[MAX_N], fatnum[MAX_N], fatlog[MAX_N];//記錄路徑 inline bool judge(int pos, int l, int n, int f) { if (l == fatlog[fat[pos]]) {
return n < fatnum[fat[pos]]; } return l < fatlog[fat[pos]]; } bool work() { memset(vis, false, sizeof vis); vis[0] = true; fat[0] = -1; fatnum[0] = 0; fatlog[0] = 0; if (vis[val]) return true; for (int i = 1; i <= len; i++) { int p = len-i; if (isdigit(S[p])) continue; memcpy(tmpvis, vis, sizeof vis); for (int j = 1+(i==len); j <= 9; j++) { for (int k = 0; k < N; k++) if(vis[k]) { int pos = ( k+mod[i]*(j - (i==len)) )%N; if (!tmpvis[pos] || judge(pos, i, j, k)) { tmpvis[pos] = true; //可能同時有很多邊找到了?不可能。 fat[pos] = k; fatnum[pos] = j; fatlog[pos] = i; } } if (tmpvis[val]) return true; } memcpy(vis, tmpvis, sizeof vis); } return false; } int main() { // freopen("testdata.txt", "r", stdin); while (~scanf("%s%d", S, &N)) { len = strlen(S); mod[1] = 1%N; for (int i = 2; i <= len; i++) { mod[i] = mod[i-1]*10%N; } val = 0; for (int i = 1; i <= len; i++) { int p = len-i; res[p] = S[p]; if (isdigit(S[p])) { val += (S[p]-'0')*mod[i]%N, val %= N; } else if (S[p] == '?') { if (i == len) { val += mod[i]%N, val %= N; res[p] = '1'; } else { res[p] = '0'; } } } val = (N-val)%N; res[len] = '\0'; // printf("%s\n", res); bool ans = work(); if (!ans) { puts("*"); continue; } int tmp = val; while (fat[tmp] != -1) { int f = fat[tmp]; int l = fatlog[tmp]; int n = fatnum[tmp]; int pos = len-l; res[pos] = n + '0'; tmp = f; } // printf("%s\n", S); printf("%s\n", res); // puts(""); } return 0; } /* 1??????????????????????????????? 2 ???????????????????????????????1 2 ?294?? 17 9999??????? 81 */
View Code