• [NOI2011]Noi嘉年华


    题解:
    我们设计状态方程如下:
    num[i][j]表示从时间i到j中有多少个
    pre[i][j]表示时间1~i中,A选了j个时的B能选的数量的最大值.
    nex[i][j]表示时间i~cnt中,A选了j个时的B能选的数量的最大值.
    mus[i][j]表示从时间i到j的保证选时,A和B选的数量中的较小值的最大值.
    ①对于num数组直接可以暴力求,没问题.
    ②对于pre和nex数组在这里就只讲pre的转移,nex的转移类似.
    pre[i][j]=max(pre[i-1][j],pre[k][j]+num[k][i],pre[k][j-num[k][i]]);(1<=k<i)
    就是分成不管i时间,或者从时间k到i的都由B选,或者从时间k到i的都由A选三种情况
    ③对于mus数组,我们得到转移方程mus[i][j]=max(min(x+y,pre[i][x]+num[i][j]+nex[j][y])),x表示时间1~i中A选x个,y表示时间j~cnt中A选y个,中间num[i][j]个由B选.这样暴力转移的话是O(n^4)的,时间上是不允许的,那么我们观察转移方程,当x增大时,y只有单调递减答案才会更优,因为如果x增大且y也增大的话,表示A选的越来越多,B选的越来越少,显然答案不会更优的,所以我们维护一个y的单调递减的指针来转移就可以了,时间O(n^3).
    ④对于第一问的答案就是max(min(pre[i][j],j)),枚举时间i和A选的个数j来得到最优解.
    然后对于第二问我们对于一个活动l~r,答案为max(mus[i][j]),1<=i<=l,r<=j<=cnt.

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<stack>
    #define min(a,b) ((a)<(b)?(a):(b))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define MAXN 10100
    #define RG register
    #define LL long long int
    using namespace std;
    const int INF=1e9;
    struct node{
      int l,r;int id;
    }t[1010];
    int n;
    int num[1010][1010];//从时间i到j中有多少个
    int pre[1010][1010];//时间1~i中,A选了j个时的B能选的数量的最大值.
    int nex[1010][1010];//时间i~n中,A选了j个时的B能选的数量的最大值.
    int mus[1010][1010];//从时间i到j的保证选时,A和B选的数量中的较小值的最大值.
    int st[MAXN],cnt;
    int ans[MAXN];
    int main()
    {
      freopen("1.in","r",stdin);
      scanf("%d",&n);
       for(int i=1;i<=n;i++){
        scanf("%d%d",&t[i].l,&t[i].r);t[i].r+=t[i].l;t[i].id=i;
        st[++cnt]=t[i].l;st[++cnt]=t[i].r;
      }
      sort(st+1,st+cnt+1);cnt=unique(st+1,st+cnt+1)-st-1;
      for(int i=1;i<=n;i++){
        t[i].l=lower_bound(st+1,st+cnt+1,t[i].l)-st;
        t[i].r=lower_bound(st+1,st+cnt+1,t[i].r)-st;
        }
      for(int i=1;i<=cnt;i++)
        for(int j=1;j<=t[i].l;j++)
          for(int k=t[i].r;k<=cnt;k++)
    	num[j][k]++;
      for(int i=1;i<=cnt;i++)
        for(int j=1;j<=n;j++)
          pre[i][j]=nex[i][j]=-INF;
      pre[0][0]=nex[cnt+1][0]=0;
      for(int i=1;i<=cnt;i++){
        for(int j=0;j<=num[1][i];j++)
          pre[i][j]=max(pre[i-1][j],pre[i][j]);
        for(int j=0;j<=num[1][i];j++){
          for(int k=1;k<i;k++){
    	pre[i][j]=max(pre[k][j]+num[k][i],pre[i][j]);
    	if(j>=num[k][i]) pre[i][j]=max(pre[k][j-num[k][i]],pre[i][j]);
          }
        }
      }
      for(int i=cnt;i>=1;i--){
        for(int j=0;j<=num[i][cnt];j++)
          nex[i][j]=max(nex[i+1][j],nex[i][j]);
        for(int j=0;j<=num[i][cnt];j++){
          for(int k=cnt;k>i;k--){
    	nex[i][j]=max(nex[k][j]+num[i][k],nex[i][j]);
    	if(j>=num[i][k]) nex[i][j]=max(nex[k][j-num[i][k]],nex[i][j]);
          }
        }
      }
      for(int i=1;i<=cnt;i++)
        for(int j=i+1;j<=cnt;j++)
          {
    	for(int x=0,y=n;x<=n;x++){
    	  while(y){
    	    int val1=min(x+y,pre[i][x]+num[i][j]+nex[j][y]);
    	    int val2=min(x+y-1,pre[i][x]+num[i][j]+nex[j][y-1]);
    	    if(val2>=val1) y--;else break;
    	  }
    	  mus[i][j]=max(mus[i][j],min(x+y,pre[i][x]+num[i][j]+nex[j][y]));
    	}
          }
      for(int i=1;i<=cnt;i++)
        for(int j=0;j<=num[1][i];j++)
          ans[0]=max(ans[0],min(pre[i][j],j));
      for(int i=1;i<=n;i++)
          for(int j=t[i].l;j>=1;j--)
    	for(int k=t[i].r;k<=cnt;k++)
    	  ans[i]=max(ans[i],mus[j][k]);
      for(int i=0;i<=n;i++) printf("%d
    ",ans[i]);
      return 0;
    }
    
  • 相关阅读:
    JS高程3:面向对象的程序设计——理解对象
    JS高程3:函数表达式
    JS高程3:事件
    JS高程3:表单脚本
    InnoDB:表
    InnoDB:文件
    Springboot项目配置druid数据库连接池,并监控统计功能
    linux上修改mysql登陆密码
    上传本地文件到GitHub上
    logback.xml的使用,将日志异步保存到数据库中
  • 原文地址:https://www.cnblogs.com/Landlord-greatly/p/8144349.html
Copyright © 2020-2023  润新知