洛谷 P2662 牛场围栏 (同余最短路)

题目:传送门

题意

小L有N种可以建造围栏的木料,长度分别是l1,l2 … lN,每种长度的木料无限。任何一根木料最多只能削短M米,修建时,他将把所有选中的木料拼接在一起,因此围栏的长度就是他使用的木料长度之和。问不能修建的围栏长度最大是多少,若任何长度的围栏都能修建,就输出 -1,或者不能修建的这个最大值不存在(也就是无穷大)也输出 -1.

1 < N < 100, 0 < M < 3000

思路

考虑输出 -1 的情况:

①:若某根木棒长度等于 1 或者削短后等于 1,那么所有的长度都能被表示出来,那就输出 -1.

②:若 gcd({l1, l1 - 1,.... l1 - m, l2,..... l2 - m, … lN, ..... lN - m}) > 1,也就是所有数的 gcd 都大于 1,那么不能被表示的是无穷大的,我们设 q 为所有数的 gcd,那么任意 % q != 0 的长度都不能被修建,显然这个数是无穷大的。

剩下的就是有解的情况。

我们设 dis[i] 表示由 n 种木棒和他们削短 1 ~ m 之后的木棒中选定一些能凑出来的 % (min({l1, l2, l3 .. lN}-m) 等于 i 的最小的数,那最大不能建成的就是 max{dis[i] - ( min(l1,l2..lN) - m ) } 。

 

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define INF INT_MAX
#define inf LLONG_MAX
#define PI acos(-1)
#define fir first
#define sec second
using namespace std;

const int N = 2500010;
const LL mod = 1e9 + 7;

int n, m, a[500], dis[N << 1], vis[N << 1], tot;
int fir[N], nx[N << 1], to[N << 1], cost[N << 1];

void add(int u, int v, int w) {
    nx[++tot] = fir[u];
    fir[u] = tot;
    to[tot] = v;
    cost[tot] = w;
}

void spfa() {
    queue < int > q;
    mem(dis, 0x3f3f3f3f);
    mem(vis, 0);
    vis[0] = 1;
    dis[0] = 0;
    q.push(0);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int e = fir[u]; e; e = nx[e]) {
            int v = to[e], w = cost[e];
            if(dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if(!vis[v]) {
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
}

int main() {

    scanf("%d %d", &n, &m);

    rep(i, 1, n) scanf("%d", &a[i]);

    sort(a + 1, a + 1 + n);

    if(a[1] - m <= 1) {
        puts("-1");
        return 0;
    }

    rep(i, 1, n) {
        rep(j, max(a[i] - m, a[i - 1] + 1), a[i]) {
            rep(k, 0, a[1] - m - 1) {
                add(k, (k + j) % (a[1] - m), j);
            }
        }
    }

    spfa();

    int ans = 0;

    rep(i, 1, a[1] - m - 1) {
        if(dis[i] > 100000000) {
            puts("-1");
            return 0;
        }
        ans = max(ans, dis[i] - (a[1] - m));
    }
    printf("%d
", ans);
    return 0;
}
一步一步,永不停息
原文地址:https://www.cnblogs.com/Willems/p/12622363.html