zoukankan      html  css  js  c++  java
  • 【[ZJOI2005]午餐】

    首先我们得贪心一下,让吃饭时间较长的人排在队首

    去抄一段贪心的证明吧

    现在研究在一个队伍里的人有什么性质

    可以发现道题里也有一个不变量,就是对于队伍里的前(i)个人,不管他们排队的顺序如何,(a[i])的前缀和(s[i])是不会变的,第(i)个人会在(s[i]+b[i])时刻吃完,这前(i)个人的吃饭时间是(max(s[j]+b[j]))

    现在可以回到贪心的问题上了,假设对于两个相邻的人(i)(i+1),如果(a[i]==a[i+1]),那么显然让(b[i]>b[i+1])

    由上面的性质可以看到(s[i])是守恒的,那么让第(i)个人的(b[i])是前(i)个人里最小的当然就是坠吼的啦

    之后就可以dp了

    感觉自己dp的姿势不太对

    最开始yy出来的状态是(dp[i][j])表示前(i)个人里(j)个人去了一个队列时消耗时间最长的人的最小耗时

    但是这个状态显然不对,因为我们不知道这(j)个人的总的等待时间,好想没有什么办法进行转移

    于是缺一个状态就加上一维吧,那就用(dp[i][j][k])表示前(i)个人里(j)个人去了一个队列时等待时间为(k)消耗时间最长的人的最小耗时

    发现这样的话空间好像要炸的样子,尽管开滚动好像都不太行

    但是又发现第二维好像没有什么存的必要,因为转移的时候根本就跟这个队列里有多少人没有关系

    于是最后的状态就是(dp[i][j])表示前(i)个人里一个队列总等待时间为(k)消耗时间最长的人的最小耗时

    我们考虑一下如何转移,因为这两个队列本质是相同的,所以一个人有两种选择,一个就是进入在状态里表示的那个队列,在一个就是进入另一个队列

    进入状态里表示的这个队列的话,这个队列的总时长会增加,等待时间最长的人可能也会有变化

    于是就有

    [dp[i][j+a[i]]=max(dp[i-1][j],j+a[i]+b[i]) ]

    进入另外一个队列,这个队列的等待时长没有变化,但是我们需要知道另外一个队列所有人的总等待时间,由于我闷知道这个队列的总等待时间是(j),那么我们用一个前缀和就能求出来另外一个队列的总等待时间

    [dp[i][j]=max(dp[i-1][j],pre[i-1]-j+a[i]+b[i]) ]

    代码

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #define re register
    #define maxn 205
    #define INF 336860180
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    struct Node
    {
       int a,b;
    }t[maxn];
    int n;
    int dp[201][200*200+1];
    int pre[maxn];
    int o;
    inline int read()
    {
       char c=getchar();
       int x=0;
       while(c<'0'||c>'9') c=getchar();
       while(c>='0'&&c<='9')
       	x=(x<<3)+(x<<1)+c-48,c=getchar();
       return x;
    }
    inline int cmp(Node AA,Node BB)
    {
       return AA.b>BB.b;
    }
    int main()
    {
       n=read();
       for(re int i=1;i<=n;i++)
       	t[i].a=read(),t[i].b=read();
       std::sort(t+1,t+n+1,cmp);
       for(re int i=1;i<=n;i++)
       	pre[i]=pre[i-1]+t[i].a;
       memset(dp,20,sizeof(dp));
       dp[1][t[1].a]=t[1].a+t[1].b;
       for(re int i=2;i<=n;i++)
       {
       	for(re int j=0;j<=200*200;j++)
       	{
       		if(dp[i-1][j]==INF) continue;
       		dp[i][j+t[i].a]=min(max(dp[i-1][j],j+t[i].a+t[i].b),dp[i][j+t[i].a]);
       		dp[i][j]=min(dp[i][j],max(dp[i-1][j],pre[i-1]-j+t[i].a+t[i].b));
       	}
       }
       int ans=INF;
       for(re int i=1;i<=200*200;i++)
       ans=min(ans,dp[n][i]);
       std::cout<<ans;
       return 0;
    }
    
  • 相关阅读:
    Python中读取文件中的json串,并将其写入到Excel表格中
    Python中替换敏感字
    Python写一个批量生成账号的函数
    解决MySQL不允许远程连接的问题
    Jenkins安装与配置
    Jmeter监听tomcat
    onlyoffice document docker版安装使用总结
    onlyoffice-DocumentServer 的权限验证
    docker 部署es
    docker部署graylog使用教程
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207764.html
Copyright © 2011-2022 走看看