vijos 1054 牛场围栏 【想法题】

这题刚看完后第一个想到的方法是背包 但仔细分析数据范围后会发现这题用背包做复杂度很高

比如对于这样的数据

2 100

2999

2898

(如果有神犇可以用背包过掉这样的数据 请回复下背包的做法)

-----------------------------------------------------------------------------------

在翻看了vijos上自带题解区后 会发现有些人提到了最短路

设最后可用木料中最短的长度为L0 则显然若长度X可以得到 那么长度X+L0也可以得到

所以我们可以研究下在MODL0的意义下 每种长度至少要为多长可以得到

设所有可得到的长度最小值中的最大值为Y 那么Y-L0即为最后的答案

由于建图已经是O(L^2)了 因此求最短路的时候直接写不加堆优化的dijkstra总复杂度也是O(L^2)的

具体实现以及细节处理可参考代码

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define rep(i,n) for(int i=1;i<=n;++i)
#define imax(x,y) (x>y?x:y)
#define imin(x,y) (x<y?x:y)
using namespace std;
const int L=3010;
int firste[L],nexte[L*L],v[L*L],w[L*L];
int dist[L],num[L];
bool color[L],used[L];
int n,m,e=1,low=2147483647,top=0,cnt=0;
bool flag=0;
void build_edge(int x,int y,int z)
{
    ++e;
    nexte[e]=firste[x];
    firste[x]=e;
    v[e]=y;
    w[e]=z;
}
int gcd(int x,int y)
{
    if(!y)return x;
    return gcd(y,x%y);
}
bool check(int x)
{
    if(x==low)return 0;
    int tx=x%low;
    while(tx<x)
    {
        if(color[tx])return 0;
        tx+=low;
    }
    return 1;
}
int main()
{
    int x,ans=0;
    scanf("%d%d",&n,&m);
    rep(i,n)
    {
        scanf("%d",&x);
        if(x-m<=1)
        {
            printf("-1");
            return 0;
        }
        low=imin(low,x-m);
        top=imax(top,x);
        for(int j=x-m;j<=x;++j)
        color[j]=1;
    }
    for(int i=2;i<=top;++i)
        if(color[i])
        num[++cnt]=i;
    for(int i=1;i<cnt;++i)
    {
        for(int j=i+1;j<=cnt;++j)
        if(gcd(num[i],num[j])==1)
        {
            flag=1;
            break;
        }
        if(flag)break;
    }
    if(!flag)
    {
        printf("-1");
        return 0;
    }
    rep(i,cnt)
    if(check(num[i]))
    {
        int z=num[i]/low;
        for(int j=0;j<low;++j)
        {
            int y=(j+num[i])%low;
            if(y>j)
            build_edge(j,y,z);
            else
            build_edge(j,y,z+1);
        }
    }
    memset(dist,60,sizeof(dist));
    dist[0]=0;
    for(int i=1;i<low;++i)
    {
        int u=low;
        for(int j=0;j<low;++j)
            if(!used[j]&&dist[j]<dist[u])u=j;
        used[u]=1;
        for(int p=firste[u];p;p=nexte[p])
            if(dist[v[p]]>dist[u]+w[p])
            dist[v[p]]=dist[u]+w[p];
    }
    for(int i=0;i<low;++i)
    ans=imax(ans,(dist[i]-1)*low+i);
    printf("%d",ans);
    return 0;
}
时间: 2024-08-24 20:36:25

vijos 1054 牛场围栏 【想法题】的相关文章

POJ 2965 The Pilots Brothers&#39; refrigerator (想法题)

POJ 2965 题意: 输入一个形如: -+-- ---- ---- -+-- 4*4图案,+表示close,-表示open,定义一种操作为:改变某个单元格符号(+变-,-变+),同时单元格所在行与所在列的所有单元格符号都会发生改变. 求最少操作次数能使所有单元格内都是'-'.并输出要操作的单元格. 思路: 正常的做法和POJ 1573类似,dfs枚举即可,见code1. 这里提供一种高效的做法: 通过思考我们可以验证,某一个单元格内符号为'+',同时对其所在行与所在列的所有单元格进行操作(其

HDU 2410 Barbara Bennett&#39;s Wild Numbers (想法题)

题目链接:HDU 2410 Barbara Bennett's Wild Numbers 题意:给出两串数w,s(长度相同),第一串中有"?",问"?"取的值使w对应的数大于s对应的数 的最大方案数. 思路:W,S一一对应比较: 遇到第一个'?'之前比较情况 1.w[i]<s[i] 方案数0种:break: 2.w[i]>s[i] break.之后有n个''?' 方案数就有10的n次方种. 3.w[i]=s[i] 继续比较,重复1.2两个条件. 遇到'?

SGU 410 Galaxy in danger --贪心,想法题

题意:有n个星球,每个星球有Ai个人,每次有两种选择,第一是从每个星球上去掉1个人,第二个选择是选择一个星球放置一个科学家,将该星球的人数加倍,问最少多少次能够将所有星球上的人数同时变为0,并且如果步数<=1000,还要输出操作顺序. 解法:找出人数最多的那个星球,设最大人数为maxi,那么跑一个循环,每次该星球如果人数<maxi,那么能加倍就加倍到离maxi最近的位置,然后计算他们的差,比如2 1035,加倍后为1024 1035,差为11,那么到时候1024减到11的时候,1035变成了2

1093. Count PAT&#39;s (25)想法题吧,算是排列组合吧

1093. Count PAT's (25) 时间限制 120 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CAO, Peng The string APPAPT contains two PAT's as substrings. The first one is formed by the 2nd, the 4th, and the 6th characters, and the second one is formed by the 3r

HDU 2410 Barbara Bennett&amp;#39;s Wild Numbers (想法题)

题目链接:HDU 2410 Barbara Bennett's Wild Numbers 题意:给出两串数w,s(长度同样),第一串中有"?",问"?"取的值使w相应的数大于s相应的数 的最慷慨案数. 思路:W,S一一相应比較: 遇到第一个'?'之前比較情况 1.w[i]<s[i] 方案数0种:break: 2.w[i]>s[i] break. 之后有n个''?' 方案数就有10的n次方种. 3.w[i]=s[i] 继续比較.反复1.2两个条件. 遇到'

HDU 4972 Bisharp and Charizard 想法题

Bisharp and Charizard Time Limit: 1 Sec  Memory Limit: 256 MB Description Dragon is watching NBA. He loves James and Miami Heat. Here's an introduction of basketball game:http://en.wikipedia.org/wiki/Basketball. However the game in Dragon's version i

HDU - 5806 NanoApe Loves Sequence Ⅱ 想法题

http://acm.hdu.edu.cn/showproblem.php?pid=5806 题意:给你一个n元素序列,求第k大的数大于等于m的子序列的个数. 题解:题目要求很奇怪,很多头绪但写不出,选择跳过的题,简称想法题. 首先考虑区间的更新方法:区间左端l不动,右端r滑动, 滑到有k个数>=m时,此区间符合条件,并且发现右端点再往右滑到底,此条件一直符合(因为若加入的数小于"第K大的数",则毫无影响.若不然,加入该数会产生一个新的第k大数,保证>="第K大

牛场围栏(vijos 1054)

题目大意: 给出N种木棍(每种木棍数量无限)的长度(<=3000),每根木棍可以把它切掉[1,M]的长度来得到新的木棍. 求最大的不能被组合出来的长度. 如果任何长度都能组合出来或者最大值没有上限输出-1.    (1<N<100, 0<=M<3000), 解题过程: 1.这题就是USACO 4.1的麦香牛块 ,只不过 数据 加强了下. 当时就把它当做 背包 来做,然后确定一个较大的范围(当时就选了60000),求出这个范围里的长度能否都被组合出来,如果能就输出-1. 否则输

牛场围栏

题目背景 小L通过泥萌的帮助,成功解决了二叉树的修改问题,并因此写了一篇论文, 成功报送了叉院(羡慕不?).勤奋又勤思的他在研究生时期成功转系,考入了北京大学光华管理学院!毕业后,凭着自己积累下的浓厚经济学与计算机学的基础,成功建设了一个现代化奶牛场! 题目描述 奶牛们十分聪明,于是在牛场建围栏时打算和小L斗智斗勇!小L有N种可以建造围栏的木料,长度分别是l1,l2 … lN,每种长度的木料无限. 修建时,他将把所有选中的木料拼接在一起,因此围栏的长度就是他使用的木料长度之和.但是聪明的小L很快