牛场围栏(余数+最短路)

今天学了不少新东西,闲着无聊都发了两发博客了,明明这只是XXY的基础题
题目描述
奶牛们十分聪明,于是在牛场建围栏时打算和小L斗智斗勇!小L有N种可以建造围栏的木料,长度分别是l1,l2 … lN,每种长度的木料无限。

修建时,他将把所有选中的木料拼接在一起,因此围栏的长度就是他使用的木料长度之和。但是聪明的小L很快发现很多长度都是不能由这些木料长度相加得到的,于是决定在必要的时候把这些木料砍掉一部分以后再使用。

不过由于小L比较节约,他给自己规定:任何一根木料最多只能削短M米。当然,每根木料削去的木料长度不需要都一样。不过由于测量工具太原始,小L只能准确的削去整数米的木料,因此,如果他有两种长度分别是7和11的木料,每根最多只能砍掉1米,那么实际上就有4种可以使用的木料长度,分别是6, 7,10, 11。

因为小L相信自己的奶牛举世无双,于是让他们自己设计围栏。奶牛们不愿意自己和同伴在游戏时受到围栏的限制,于是想刁难一下小L,希望小L的木料无论经过怎样的加工,长度之和都不可能得到他们设计的围栏总长度。不过小L知道,如果围栏的长度太小,小L很快就能发现它是不能修建好的。因此她希望得到你的帮助,找出无法修建的最大围栏长度。

这一定难不倒聪明的你吧!如果你能帮小L解决这个问题,也许他会把最后的资产分给你1/8哦!

输入输出格式
输入格式:
输入的第一行包含两个整数N, M,分别表示木料的种类和每根木料削去的最大值。以下各行每行一个整数li(1< li< 3000),表示第i根木料的原始长度。

输出格式:
输出仅一行,包含一个整数,表示不能修建的最大围栏长度。如果任何长度的围栏都可以修建或者这个最大值不存在,输出-1。

输入输出样例
输入样例#1:
2 1
7 11
输出样例#1:
15
说明
40 % :1< N< 10, 0< M< 300

100 % :1< N< 100, 0< M< 3000

题意:

用一堆整数S相加组成新数,每个可以用任意次数,求最大的不能组成的数。

思路:

  • 首先判掉两种情况:1可以组成任何数,2不能组成的数无限大。

  • 第一种情况就是在原始的整数集合S中有1。第二种情况是S中所有数的GCD大于1,所以所有不能被GCD整除的数都无法组成

  • 然后终于到了求最大无法构成的数了。首先我们假设S中所有数存在l[]数组中,minl是l[]里的最小值。所以所有可以组成的数都可以%minl变成0~minl-1的一个数。然而这有什么用呢?我们可以记录一个dis[]数组,用来存能被组成%minl值为i的数中最小的那个,因为只要最小的那个能被组成了,在这个最小数基础上加上minl,就可以保证与他同于的比他大的数全都可以被组成。所以所有dis[]中存的最小值减去minl就是不能取到的最大值,把所有的取min就是最终答案。

  • 那么如何求最小值呢?可以联想到最短路算法(根本联想不到,我第一次看到题解里的SPFA是懵逼的)。具体实现挺简单的,就像普通可行性DP一样转移就好了

上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 3010;
int n, m;
vector<int> l;
int dis[N];
bool inq[N];

int GCD(int x, int y)
{
    if (y == 0) return x;
    return GCD(y, x%y);
}

void SPFA()
{
    memset(dis, 0x3f, sizeof(dis));
    memset(inq, 0, sizeof(inq));
    queue<int> q;
    q.push(0); dis[0] = 0; inq[0] = 1;
    while (!q.empty()){
        int u = q.front();
        inq[u] = 0;
        q.pop();
        for (int i = 1; i < n; i++){
            int v = (u+l[i])%l[0];
            if (dis[v] > dis[u]+l[i]){
                dis[v] = dis[u]+l[i];
                if (!inq[v]){
                    inq[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++){
        int x;
        scanf("%d", &x);
        for (int j = 0; j <= min(m, x-1); j++)
            l.push_back(x-j);
    }
    sort(l.begin(), l.end());
    n = unique(l.begin(), l.end())-l.begin();
    if (l[0] == 1){
        printf("-1");
        return 0;
    }
    int d = l[0];
    for (int i = 1; i < n; i++){
        d = GCD(d, l[i]);
        if (d == 1) break;
    }
    if (d > 1){
        printf("-1");
        return 0;
    }
    SPFA();
    int ans = 0;
    for (int i = 0; i < l[0]; i++)
        ans = max(ans, dis[i]-l[0]);
    printf("%d", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyyxyyx/article/details/81366328