• DP2 1008


    hotel

    Miss D和gnaw出去玩的时候,发现一个很奇怪的旅馆,宾馆老板特别喜欢数字4和7,如果一个房间里住4或7个人,他就会很开心,不然他甚至不想让这个房间里住人。现在告诉你每个房间住的人数(7人以内),将一个原在i号房间的人移动到j房间的代价是abs(i-j),要想能满足老板的要求,花费的代价是多少?

    输入
    第一行一个数n,表示房间数
    第二行n个数,表示每个房间原先住着的人数
    输出
    一个数,表示按照老板要求最小的花费
    如果不能按要求分配,输出-1

    100%:1<=n<=1e5

    题解

    状态设计是最难想的,f[i][j]为第i个房间向后一个房间移动j个人且第i个房间满足条件的最小操作数。

    因为一个房间最多7个人,所以最多向后移动7个人,不过也看是移进来,所以第二维14,以7为基底。

    在转移的时候枚举从这个房间转出和下个房间转出多少人,这样可以考虑到所有情况。

    最后从第n-1个房间找答案,因为第n个房间不能转出。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int maxn=100005;
    const int inf=1061109567;
    int n,a[maxn];
    int f[maxn][20];//从第i个房间向i+1的房间出去j个人的最小操作(j<7为进入 
    
    template<class T>inline void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x = f ? -x : x ;
    }
    
    int abs(int x){return x<0 ? -x : x ;}
    bool cx(int x){
        if(!x||x==4||x==7) return true;
        return false;
    }
    
    int main(){
        freopen("hotel.in","r",stdin);
        freopen("hotel.out","w",stdout);
        read(n);
        for(int i=1;i<=n;i++) read(a[i]);
        memset(f,0x3f,sizeof(f));
        f[0][7]=0;
        for(int i=0;i<n;i++)
         for(int j=0;j<=14;j++)
          if(f[i][j]!=inf){
              int in=j-7;
              for(int k=0;k<=14;k++){
                  int out=k-7;
                  if(cx(a[i+1]+in-out))
                      f[i+1][k]=min(f[i+1][k],f[i][j]+abs(out));
                }
            }
        int ans=inf;
        for(int i=0;i<=14;i++)
         if(cx(a[n]+i-7))//n没有后继,所以从n-1找答案 
          ans=min(ans,f[n-1][i]);
        printf("%d", ans==inf ? -1 : ans);
    }
    hotel

    gift

    Gnaw给Miss D准备了一个长为n的礼物,还让m个朋友来帮他完成这个礼物,每个人开始是站在位置p,最多可以装扮连续的长为x的部分,一个人可以不参与,一旦参与,他装扮的部分一定包含他一开始站的位置。每个人装扮长为1的部分能让整个礼物增加y的美丽度,gnaw想让整个礼物的美丽值最高,会是多少?

    输入
    第一行两个整数n m,表示礼物长度和朋友数。
    接下来n行,每行3个整数,分别为一个人最多装扮长度,单位美丽值和初始位置。
    输出
    一个整数,表示整个礼物最大的美丽值

    1 <= n <= 16 000
    1 <= m <= 100
    1 <= y <= 10 000

    ps:只要p在他涂的区间就合法。

    题解

    可以想到f[i][j]表示前i个人涂前j个单位的最大美丽值,枚举区间右端点j和左端点k(k,j]。

    f[i][j]=max(f[i-1][k]+(j-k)*y) k+1<=p<=j并且区间长度不超过j

    这样就能保证区间一定选到了p

    变一下形f[i][j]=max(f[i-1][k]-ky+jy)

    jy是定值,所以只要f[i-1][k]-ky最大即可,可以用单调队列维护(滑动区间求最大值)

    不过发现要对人按p排序,因为如果前面有人能够放而且对某个状态没有影响,那么那个状态就可以更大。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int maxn=16005;
    const int maxm=105;
    int n,m;
    int f[maxm][maxn];//前i个人装饰前j个单位的最大值 
    int h,t,s[maxn];
    struct person{
        int x,y,pos;
        bool operator < (const person a){return pos<a.pos;}
    }a[maxm];
    
    template<class T>inline void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x = f ? -x : x ;
    }
    
    int get(int i,int j,int w){return f[i][j]-j*w;}
    
    int main(){
        freopen("gift.in","r",stdin);
        freopen("gift.out","w",stdout);
        read(n);read(m);
        for(int i=1;i<=m;i++) read(a[i].x),read(a[i].y),read(a[i].pos);
        sort(a+1,a+m+1);
        for(int i=1;i<=m;i++){
            h=1,t=0;
            for(int j=0;j<=n;j++){
                f[i][j]=max(f[i-1][j],f[i][j-1]);//前缀求最大值 
                if(j<a[i].pos&&j+a[i].x>=a[i].pos){//把上一层的f放进去 
                    while(h<=t&&get(i-1,s[t],a[i].y)<get(i-1,j,a[i].y)) t--;
                    s[++t]=j;
                }
                if(j>=a[i].pos&&j<a[i].pos+a[i].x){//右端点在pos后才更新,保证选择了pos 
                    while(h<=t&&s[h]+a[i].x<j) h++;
                    f[i][j]=max(f[i][j],get(i-1,s[h],a[i].y)+j*a[i].y);
                }
            }
        }
        printf("%d",f[m][n]);
    }
    gift
  • 相关阅读:
    Scala入门基础1
    LitePal数据库的基本操作
    Android操作SQLate数据库
    Android广播的使用(自定义广播和本地广播)
    Android广播的使用(动态注册和静态注册)
    Android碎片的使用
    linux--硬链接与软连接
    linux下python环境的搭建
    系统时间的修改
    linux命令--文件和目录管理
  • 原文地址:https://www.cnblogs.com/sto324/p/11640146.html
Copyright © 2020-2023  润新知