uva 1341 - Different Digits(数论+bfs)

题目链接:uva 1341 - Different Digits

题目大意:给定一个数字n,要求求一个数字m,m可以整除n,并且尽量组成的数字种类(0~9)尽量少,在种类相同的情况下数值尽量小。

解题思路:可以证明两种数字肯定可以组成m,假设有数字k,一种数字可以有k,kk,kkk,kkkk,…整除n剩的数一定在0~n-1之间,所以肯定存在两个由k数字组成的数字同模,那么这两个数相减所得到的数即使kkk00000,两种数字。于是肯定了范围,枚举数字,然后用bfs获取答案,维护最小值即可。

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>

using namespace std;

const int maxn = 65536;
int n, vis[maxn+10];

struct state {
    int key, len, vec[maxn];
    state () {
        key = 0;
    }

    bool operator < (const state& a) {
        if (a.key == 0)
            return true;
        if (key == 0)
            return false;

        if (key != a.key)
            return key < a.key;

        if (len != a.len)
            return len < a.len;

        int l = len;
        for (int i = 0; i < l; i++)
            if (vec[i] != a.vec[i])
                return vec[i] < a.vec[i];
        return false;
    }
};

struct node {
    int mod, len, num;
    void set (int mod, int num, int len) {
        this->mod = mod;
        this->num = num;
        this->len = len;
    }
}que[maxn*2];

void put (int d, state& w, int x) {
    if (d < 0 || x < 0)
        return;
    w.vec[d] = que[x].num;
    put(d-1, w, vis[que[x].mod]);
}

state judge (int a, int b) {
    int head = 1, rear = 1;
    memset(vis, -1, sizeof(vis));

    state w;
    node u, v;
    w.key = (a==b?1:2);

    if (a) {
        que[rear++].set(a%n, a, 1);
        vis[a%n] = 0;
    }

    if (b) {
        que[rear++].set(b%n, b, 1);
        vis[b%n] = 0;
    }

    while (head < rear) {
        u = que[head++];

        if (u.mod == 0) {
            w.len = u.len;
            put(u.len-1, w, head-1);
            return w;
        }

        for (int i = 0; i < w.key; i++) {
            int t = (i?b:a);
            v.set((u.mod*10+t)%n, t, u.len+1);

            if (vis[v.mod] != -1)
                continue;

            vis[v.mod] = head-1;;
            que[rear++] = v;
        }
    }
    w.key = 0;
    return w;
}

int main () {
    while (scanf("%d", &n) == 1 && n) {
        state ans;

        for (int i = 1; i <= 9; i++) {
            state c = judge(i, i);
            if (c < ans)
                ans = c;
        }

        if (ans.key == 0) {
            for (int i = 0; i <= 9; i++) {
                for (int j = i+1; j <= 9; j++) {
                    state c = judge(i, j);
                    if (c < ans)
                        ans = c;
                }
            }
        }
        for (int i = 0; i < ans.len; i++)
            printf("%d", ans.vec[i]);
        printf("\n");
    }
    return 0;
}

uva 1341 - Different Digits(数论+bfs)

时间: 2024-08-06 07:30:16

uva 1341 - Different Digits(数论+bfs)的相关文章

UVA 1341 - Different Digits(数论)

UVA 1341 - Different Digits 题目链接 题意:给定一个正整数n,求一个kn使得kn上用的数字最少,如果相同,则输出值最小的 思路: 首先利用鸽笼原理证明最多需要2个数字去组成 设一个数字k,组成k,kk,kkk,kkkk... %n之后余数必然在0 - (n - 1)之间,所以必然能选出两个余数相等的数字相减为0,这个数字就是由0和k组成的. 因此只要考虑一个数字和两个数字的情况,去bfs,记忆化余数,因为余数重复必然形成周期了 代码: #include <stdio.

uva 718 - Skyscraper Floors(数论+bfs)

题目链接:uva 718 - Skyscraper Floors 题目大意:一栋大楼,有F层楼,E个电梯,现在要从A层到B层,问是否可行,每个电梯给出Xi和Yi,代表这个电梯可以到达的层数Yi+k?Xi(k≥0) 解题思路:建图,以A,B以及电梯为节点建图,将可以到达A,B这两层的电梯与这两点建边,在将两两电梯可以达到同一层的建边,判断方法为:Yi+aXi=Yj+bXj,移项得:aXi+bXj=Yj?Yi,即是一个线性方程,用拓展欧几里得算法求出通解的形式,判断是否存在通解在0~F之间即可. #

uva 10560 - Minimum Weight(数论)

题目连接:uva 10560 - Minimum Weight 题目大意:给出n,问说至少需要多少个不同重量的砝码才能称量1~n德重量,给出所选的砝码重量,并且给出k,表示有k个重量需要用上述所选的砝码测量. 解题思路:重量为1的砝码肯定要选,它可以表示到1的重量,那么下一个砝码的重量肯定选择3(2?1+1),这样1,3分别可以用一个砝码表示,而2,4分别为3-1和3+1,这样1~4的重量也都可以表示.于是有公式ai=si?1?2+1. #include <cstdio> #include &

uva 11105 - Semi-prime H-numbers(数论)

题目链接:uva 11105 - Semi-prime H-numbers 题目大意:H-number为4?k+1(k为非负数),H-composites为因子中含有H-number(不包括自己本身)的数,反之久是H-prime,给定n,求有多少H-composites. 解题思路:首先用筛选法求出范围内的H-prime,然后枚举两个判断乘积是否在范围内. #include <cstdio> #include <cstring> const int maxn = 1e6+5; ty

UVA 11754 - Code Feat(数论)

UVA 11754 - Code Feat 题目链接 题意:给定一个c个x, y1,y2,y3..yk形式,前s小的答案满足s % x在集合y1, y2, y3 ... yk中 思路:LRJ大白例题,分两种情况讨论 1.所有x之积较小时候,暴力枚举每个集合选哪个y,然后中国剩余定理求解 2.所有x之积较大时候,选定一个k/x尽可能小的序列,枚举x * t + y (t = 1, 2, 3...)去暴力求解. 代码: #include <stdio.h> #include <string.

UVA 718 - Skyscraper Floors(数论)

UVA 718 - Skyscraper Floors 题目链接 题意:在一个f层高的楼上,有e个电梯,每个电梯有x,y表示y + k * x层都可以到,现在要问从a层能否到达b层(中间怎么换乘电梯不限制) 思路:对于两个电梯间能不能换乘,只要满足y[i] + xx x[i] == y[j] + yy y[j].然后移项一下,就可以用拓展欧几里得求解,进而求出x,y的通解,然后利用通解范围x' >= 0, y' >= 0, x[i] x' + y[i] <= f, x[j] y' + y

UVA 10692 - Huge Mods(数论)

UVA 10692 - Huge Mods 题目链接 题意:求a0a1a2...mod m 思路:直接算肯定不行,利用欧拉定理ab=a(b mod phi(m) + phi(m))(b>=phi(m)),对指数进行降值处理,然后就可以利用快速幂去计算了,计算过程利用递归求解. 代码: #include <stdio.h> #include <string.h> const int N = 1005; int phi[N * 10], vis[N * 10], m, n, a[

UVA 10623 - Thinking Backward(数论)

UVA 10623 - Thinking Backward 题目链接 题意:给定一个数量,求用圆,椭圆,三角形分割平面,分割出该数量,输出所有情况 思路:有公式2 + 2m(m-1) + n(n-1) + 4mn + 3p(p-1) + 6mp + 6np 由于m和p都是[0,100],所以可以枚举m和p,去求出n,然后判断合不合适 代码: #include <stdio.h> #include <string.h> #include <math.h> #include

uva 11728 - Alternate Task(数论)

题目链接:uva 11728 - Alternate Task 题目大意:给出S,求N,要求N所有的因子和为S. 解题思路:枚举因子i,所有整除i的数和加上i. #include <cstdio> #include <cstring> const int N = 1005; int n, c[N], v[N]; void init () { memset(c, 0, sizeof(c)); memset(v, -1, sizeof(v)); for (int i = 1; i &l