zoukankan      html  css  js  c++  java
  • 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;
    }

     另外 vijos1065 的思路也与此类似 只不过更加直接了

  • 相关阅读:
    Vue组件
    Vue内置指令
    [vue插件]基于vue2.x的电商图片放大镜插件
    Vue过渡与动画
    一个 VUE 组件:实现子元素 scroll 父元素容器不跟随滚动(兼容PC、移动端)
    ORM进阶之Hibernate中对象的三大状态解析
    jQuery的CSS操作
    SqlCommand.DeriveParameters failed
    Web Service学习-CXF开发Web Service实例demo(一)
    去哪网实习总结:如何配置数据库连接(JavaWeb)
  • 原文地址:https://www.cnblogs.com/sagitta/p/4604972.html
Copyright © 2011-2022 走看看