[hdu4474]Yet Another Multiple Problem——同余定理+数位广搜 大佬们的博客 Some Links

题目大意:

给定n和若干个0-9数字,要求找到最小的n的倍数满足这个数中不出现给定的数字。

思路:

可以说这是一道很好的题目了。显然这种题和数位有关,所以我们可以猜测一下答案可能会很大,用普通的爆搜或者是DP是过不了的。
考虑从满足限制的数字中选择数字一个一个地添加到后面,我们要求最小的倍数,即在满足条件下第一个模n为0的数,根据同余定理有:

( a 10 + b ) % n a 10 % n + b % n

可以得到一个结论,即最终答案的前面的状态必定在同余意义下是所有满足情况的数的最小值,若它不是最小值,那么最小值可以在后面加上相同的数字然后达到是 n 的倍数,从而比刚才假设的最优答案更优。所以我们要求的就是在模 n 意义下每个数的最小值,又因为 n 的范围不大,总共的状态就只有 n 个,所以只需要广搜就好了。

/*=======================
 * Author : ylsoi
 * Problem : hdu4474
 * Algorithm digit bfs
 * Time 2018.7.17
 * ====================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("hdu4474.in","r",stdin);
    freopen("hdu4474.out","w",stdout);
}

const int maxn=1e6+10;
int n,t,tot,ans[maxn];
bool vis[11],b[maxn];

struct node{int val,digit,las;}
a[maxn];

bool bfs(){
    queue<int>qu;
    REP(i,1,9)if(!vis[i]){
        qu.push(++tot);
        a[tot]=(node){i%n,i,0};
        b[i%n]=1;
    }
    while(qu.size()){
        int u=qu.front(); qu.pop();
        if(!a[u].val){
            int len=0;
            while(u!=0){
                ans[++len]=a[u].digit;
                u=a[u].las;
            }
            putchar(' ');
            for(int i=len;i>=1;--i)putchar(ans[i]+48);
            putchar('\n');
            return true;
        }
        REP(i,0,9)if(!vis[i]){
            int c=(a[u].val*10+i)%n;
            if(b[c])continue;
            b[c]=1;
            a[++tot]=(node){c,i,u};
            qu.push(tot);
        }
    }
    return false;
}

int main(){
    File();
    int cas=0;
    while(~scanf("%d%d",&n,&t)){
        ++cas;
        tot=0;
        printf("Case %d:",cas);
        memset(b,0,sizeof(b));
        memset(vis,0,sizeof(vis));
        REP(i,1,t){
            int u;
            scanf("%d",&u);
            vis[u]=1;
        }
        if(!bfs())puts(" -1");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81080125
今日推荐