• 洛谷 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;
    }
    一步一步,永不停息
  • 相关阅读:
    希望多年以后的自己不再如此迷茫
    【转载】撒旦(Satan 4.2)勒索病毒最新变种加解密分析
    java单例模式
    关于double/float 两种基本类型精度丢失的总结
    关于ecplise中一些很实用的技巧
    安装SQL Server和卸载SQL Server步骤
    我进入部门的第一周
    mysql数据库在Linux和windows下免安装实现以及框架开发碰到的问题
    jenkins发布docker到mesos
    u盘作为git仓库,完成不同地方的代码同步
  • 原文地址:https://www.cnblogs.com/Willems/p/12622363.html
Copyright © 2020-2023  润新知