zoukankan      html  css  js  c++  java
  • 20190817DP练习

    ennn,今天是0x125E591的生日 大家+1s.-xcc

    T1:LG奇怪的电梯.

    S1:对每一个点建合法的边,跑最短路.(ps:因为不是DP,不上码了.)

    T2:LG尼克的任务.

    S2:遗憾考试卡在这个题上,最后连暴力都没打.看到给定一段段区间关联交并问题,自然地联想到了昨天做LG上的饥饿的奶牛   ,于是设了f[ i ][ 0/1]表示为第 i 段选或不选并保证前 i 段都会合法覆盖的情况下最少工作时间,f[ i ][ 0 ]则枚举i之前的区间k能覆盖i区间的进行f[ i ][ 0 ]=max{f[k][1]}的转移,f[ i ][ 1 ]则变得不好处理,要去找不覆盖i区间的区间k,并找到最小代价v将Σk覆盖,f[ i ][1]=max(f[ i ][ 1],v+time[i]),最后发现v怎么也找不出来,并发现后面的选择还会影响前面的状态,这样推dp显然是不行的.看了题解,发现果然要倒推,因为后面的状态影响前面的状态.记录此时不是任务开头,就f[ i ]=f[ i+1]+1,有任务就执行,f[ i ]=Σmax(f[ i ],f[ i+len]),建议调试样例,自然会懂.

    总结:①平静下来,不会正解打暴力.②MS:code once,think twice.

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define e exit(0)
    #define R register
    int n,k,id=1,sum[10010],f[10010];
    struct bian{
        int L,v;
    }len[10010];
    bool cmp(bian a,bian b){return a.L>b.L;}
    int main()
    {
        freopen("LIGNJA.in","r",stdin);
        freopen("LIGNJA.out","w",stdout);
        scanf("%d%d",&n,&k);
        for(R int i=1;i<=k;++i){
            scanf("%d%d",&len[i].L,&len[i].v);
            ++sum[len[i].L];
        }
        sort(len+1,len+1+k,cmp);
        for(R int i=n;i>=1;--i){
            if(!sum[i])
                f[i]=f[i+1]+1;
            else{
                for(R int j=1;j<=sum[i];++j){
                    f[i]=max(f[i],f[i+len[id].v]);
                    ++id;
                }
            }
        }
        printf("%d",f[1]);
    }

    T5:LGP1233

    S5:不知道为什么考试脑抽,对于双要求的最长不下降子序列,自己就将两个要求一起判断求???其实要联想到LG友好城市.将一个要求sort确定下来,另一个在此基础上求.

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define e exit(0)
    #define R register
    int n,q[5010],lenth;
    struct bian{
        int L,W;
    }len[5010];
    bool cmp(bian a,bian b){
        if(a.L==b.L)
            return a.W<=b.W;
        else return a.L<b.L;
    }
    int find(int x)
    {
        int l=1,r=lenth;
        while(l<r){
            int mid=(l+r)>>1;
            if(q[mid]<=x) r=mid;
            else l=mid+1;
        }
        return l;
    }
    int main()
    {
        freopen("STICK.in","r",stdin);
        freopen("STICK.out","w",stdout);
        scanf("%d",&n);
        for(R int i=1;i<=n;++i)
            scanf("%d%d",&len[i].L,&len[i].W);
        sort(len+1,len+1+n,cmp);
        q[++lenth]=len[1].W;
        for(R int i=2;i<=n;++i)
        {
            if(len[i].W<q[lenth])
                q[++lenth]=len[i].W;
            else if(len[i].W>=q[lenth]){
                int id=find(len[i].W);
                q[id]=len[i].W;
            }
        }
        printf("%d",lenth);
        return 0;
    }

    PS:①:当一个元素一个标志相同时,另一个标志小sort时放前,这样单调栈求最长下降子序列时长度会往小的方面发展.

       ②:二分查找找维护单调下降的序列中第一个比它小的是这样写,其他要求跟题目意思来,注意等号给左边给右边关系"比它小比它大问题".

    T4:LGP1220

    S4:太菜了,看题解才懂.设f[ L ][ R ][ 0/1 ]表示为走完区间[ L , R ]的耗电量,并且结束时人在L / R点.在转移方程中我们要体现一直走或折返走这个过程.思路转移在题解中写的很清楚了.但有几个细节蒟蒻认为比较重要,想了一下才明白.

    ① f[ L ][ R ][ 0 ]会由f[ L+1 ][ R ][ 1 ]转移过来,顺推,L由L+1转移,看似违背了后效性,其实不然,我们会发现len从小到大枚举,f[ L+1 ][ R ]会提前更新.

    ② 对于任意的f[ L ][ R ][ 0 ]不一定都有意义(可对样例的各个区间输出一下).因为开始位置决定了有些区间无法走的,这就证明了为什么初始化是有意义的.

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define re register
    long long n,c,pos[1010],sum[1010],w[1010],f[1010][1010][2];
    int main()
    {
        freopen("power.in","r",stdin);
        freopen("power.out","w",stdout);
        scanf("%lld%lld",&n,&c);
        for(re int i=1;i<=n;++i){
            scanf("%lld%lld",&pos[i],&w[i]);
            sum[i]=sum[i-1]+w[i];
        }
        memset(f,0x7f,sizeof(f));
        f[c][c][0]=f[c][c][1]=0;
        for(re int len=2;len<=n;++len)
            for(re int L=1;L+len-1<=n;++L){
                int R=L+len-1;
                f[L][R][0]=min(f[L+1][R][0]+(pos[L+1]-pos[L])*(sum[L]+sum[n]-sum[R]),f[L+1][R][1]+(pos[R]-pos[L])*(sum[L]+sum[n]-sum[R]));
                f[L][R][1]=min(f[L][R-1][1]+(pos[R]-pos[R-1])*(sum[L-1]+sum[n]-sum[R-1]),f[L][R-1][0]+(pos[R]-pos[L])*(sum[L-1]+sum[n]-sum[R-1]));
            }
        printf("%lld",min(f[1][n][0],f[1][n][1]));
        return 0;
    }

     T3:对于一个多边形来说,在该多边形内任取两点,如果这两点连成的线段落在多边形内,则称这样的多边形为凸多边形。平面上有 N 个坐标值为自然数的圆点。顶点数最多凸多边形是指由给定的圆点中的一部分组成的凸多边形,它包含最大可能的顶点数。原点,即坐标内中心(0,0)必须是顶点数最多凸多边形的一个顶点。编写程序求出这样的凸多边形的最大顶点数。注意一个多边形的连续的边不能是平行的.(好像OJ没这个题)

    S3:依旧太菜了,看题解才懂.先对坐标进行极角排序(为了保证DP的无后效性).设 f[ i ][ j ]为 i为倒数第二个点,j为倒数第一个点构成的凸多边形有最多点,对当前f[ i ][ j ],我们枚举点k,如果k , i  , j能构成凸多边形,我们进行f[ i ][ j ]=max{f[ k ][ i ]+1},即在f[ i ][ k ]构成的凸多边形加入 j点,这时f[ k ][ i ]-->f[ i][ j ].

    细节:①我们将'0' , ' n+1 '其实视为一个点(原点).所以 j 要枚举到 n+1,其实为了最后ans+1(加上原点),k从0开始枚举,是为了f[ 0 ][ i ]=1的初始化起作用.

       ②三点是否在同一凸多形,本质是用叉乘判断.对于( a,b),(c,d),(e,f),形成两个向量①( a - c, b- d),②(c - e,d-f).①x②>0即在同一凸多边形.化简为a(d-f)+c(f-b)+e(b-d)>0

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define R register
    int n,ans,f[110][110];
    struct dian{
        int x,y;
        bool operator<(const dian &a) const{
            return 1.0*y/x<1.0*a.y/a.x;
        }
    }dot[110];
    bool check(int x,int y,int z)
    {
        int a=dot[x].x,b=dot[x].y;
        int c=dot[y].x,d=dot[y].y;
        int e=dot[z].x,f=dot[z].y;
        return (a*(d-f)+c*(f-b)+e*(b-d) > 0);
    }
    int main()
    {
        freopen("POLYGON.in","r",stdin);
        freopen("POLYGON.out","w",stdout);
        scanf("%d",&n);
        for(R int i=1;i<=n;++i)
            scanf("%d%d",&dot[i].x,&dot[i].y);
        sort(dot+1,dot+1+n);
        for(R int i=1;i<=n;++i)
            f[0][i]=1;
        for(R int i=1;i<=n;++i)
            for(R int j=1;j<=n+1;++j)
                for(R int k=0;k<i;++k)
                    if(check(i,j,k))
                        f[i][j]=max(f[i][j],f[k][i]+1);
        for(R int i=1;i<=n;++i)
            ans=max(ans,f[i][n+1]);
        printf("%d",ans);
        return 0;
    }

     

  • 相关阅读:
    BZOJ 3531[Sdoi2014]旅行
    BZOJ4998 星球联盟
    BZOJ2959 长跑
    【北京集训D2T3】tvt
    [Bzoj]5343: [Ctsc2018]混合果汁
    HGOI20190810 省常中互测3
    HGOI20190809 省常中互测2
    HGOI20190808 省常中互测1
    组合排列和组合数 学习笔记
    2-SAT (two-statisfiability) 算法 学习笔记
  • 原文地址:https://www.cnblogs.com/xqysckt/p/11370152.html
Copyright © 2011-2022 走看看