Gym101889E. Enigma(bfs+数位)

Posted lubixiaosi-zhaocao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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] = ;
    //    printf("%s
", 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
", S);
        printf("%s
", res);
//        puts("");
    }
    return 0;
}
/*
1??????????????????????????????? 2

???????????????????????????????1 2

?294?? 17

9999??????? 81
*/
View Code

 

以上是关于Gym101889E. Enigma(bfs+数位)的主要内容,如果未能解决你的问题,请参考以下文章

每日dp Gym - 101889E Enigma 数位dp 记忆化搜索

Gym - 101889D:Daunting device (老司机树)

2017-2018 ACM-ICPC Latin American Regional Programming Contest GYM101889

CF Gym Dice Game BFS 暴搜

G - BFS Gym - 101755H

数位DP || Gym 101653RRamp Number