• 【同余最短路】洛谷 P2662 牛场围栏


    关于同余最短路的部分 【同余最短路】P3403跳楼机/P2371墨墨的等式

    【P2662牛场围栏】

    题目背景

    小L通过泥萌的帮助,成功解决了二叉树的修改问题,并因此写了一篇论文,

    成功报送了叉院(羡慕不?)。勤奋又勤思的他在研究生时期成功转系,考入了北京大学光华管理学院!毕业后,凭着自己积累下的浓厚经济学与计算机学的基础,成功建设了一个现代化奶牛场!

    题目描述

    奶牛们十分聪明,于是在牛场建围栏时打算和小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 

    思路

    关于同余最短路的东西已经写过了,这里直接本题相关。

    依然是由一些数字去凑一个数字的剩余系,这道题由于多了M的条件,需要先暴力把所有能用的数字求出来,并让其中最小的那个成为提供剩余系的x。

    然后跑一遍所有能用的数字,和x的剩余系建边,最后跑最短路。

    求不能凑出的最大数的时候,我们要先考虑d数组的意义。d[i]即为其他数字能凑出来的%x=i的最小数字,那么d[i]+x,d[i]+2x,d[i]+3x... d[i]以上跳所有个x都能达到。

    那么%x=i的数字,最大凑不出来的就是d[i]-x。

    那么很显然了,把所有的d[i]-x求出来,取其中最大值。

    但是还有要注意的地方,本题存在输出-1的要求。其中一种输出-1的情况是没有凑不出来的数,那么当我们能用的木料中存在长为1的,自然就能达到所有的长度。

    另一种情况是不存在这个最大值。这里有两种考虑方向,一种是求出所有数字的gcd,若其不等于1,自然有一系列没法凑出来的数字。因为能凑出来的数字一定是这个gcd的倍数,其不为一的时候必然存在凑不出来的空缺。还有一种方法是最后找ans的时候顺便看一下是否有d[i]>max(max是给d数组跑最短路前设的最大值),如果有,那么一定存在一串%x=i的数字都凑不出来。(其实这种做法大概相当于猜测利用了数据比较小)

    代码:

    #include<iostream> 
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    int n,m;
    int x,a[101];
    int ver[5100001],Next[5100001],head[2600001],edge[5100001],tot,d[2600001],vis[2600001],ans=0;
    queue<int>q;
    void add(int x,int y,int z){
        ver[++tot]=y;
        Next[tot]=head[x];
        edge[tot]=z;
        head[x]=tot;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+n+1);
        x=max(1,a[1]-m);
        if(x==1){
            printf("-1");
            return 0;
        }
        for(int i=1;i<=n;i++){
            for(int j=max(a[i-1]+1,a[i]-m);j<=a[i];j++){
                if(j!=x){
                    for(int k=0;k<x;k++){
                        add(k,(k+j)%x,j);
                    }
                }
            }
        }
        memset(d,0x3f,sizeof(d));
        d[0]=0;
        q.push(0);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=head[u];i;i=Next[i]){
                int v=ver[i],z=edge[i];
                if(d[v]>d[u]+z){
                    d[v]=d[u]+z;
                    if(!vis[v]){
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        d[x]=0;
        for(int i=1;i<x;i++){
    //        printf("%d %d
    ",i,d[i]);
            if(d[i]>100000000){
                printf("-1");
                return 0;
            }
            ans=max(ans,d[i]-x);
        }
        printf("%d",ans);
        return 0;
    }

    以上。

  • 相关阅读:
    js判断选择时间不能小于当前时间的代码
    shell脚本编程之for语句、if语句使用介绍
    linux命令 chattr超级权限控件
    教你配置linux服务器登陆欢迎信息
    PHP基础入门教程 PHP循环函数
    php获取客户端ip地址
    PHP获取域名、IP地址的方法
    两日期间的间隔
    mysql 案例 ~ pt-archiver 归档工具的使用
    mysql 案例 ~ pt修复工具的使用
  • 原文地址:https://www.cnblogs.com/chloris/p/11021092.html
Copyright © 2020-2023  润新知