[bzoj2436][NOI2011]Noi嘉年华

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/FZHvampire/article/details/51816088

2436: [Noi2011]Noi嘉年华

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 505 Solved: 361
[Submit][Status][Discuss]
Description

NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,
吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办。每
个嘉年华可能包含很多个活动,而每个活动只能在一个嘉年华中举办。
现在嘉年华活动的组织者小安一共收到了 n个活动的举办申请,其中第 i 个
活动的起始时间为 Si,活动的持续时间为Ti。这些活动都可以安排到任意一个嘉
年华的会场,也可以不安排。
小安通过广泛的调查发现,如果某个时刻,两个嘉年华会场同时有活动在进
行(不包括活动的开始瞬间和结束瞬间),那么有的选手就会纠结于到底去哪个
会场,从而变得不开心。所以,为了避免这样不开心的事情发生,小安要求不能
有两个活动在两个会场同时进行(同一会场内的活动可以任意进行)。
另外,可以想象,如果某一个嘉年华会场的活动太少,那么这个嘉年华的吸
引力就会不足,容易导致场面冷清。所以小安希望通过合理的安排,使得活动相
对较少的嘉年华的活动数量最大。
此外,有一些活动非常有意义,小安希望能举办,他希望知道,如果第i 个
活动必须举办(可以安排在两场嘉年华中的任何一个),活动相对较少的嘉年华
的活动数量的最大值。

Input

输入的第一行包含一个整数 n,表示申请的活动个数。
接下来 n 行描述所有活动,其中第 i 行包含两个整数 Si、Ti,表示第 i 个活
动从时刻Si开始,持续 Ti的时间。

Output

输出的第一行包含一个整数,表示在没有任何限制的情况下,活动较少的嘉
年华的活动数的最大值。
接下来 n 行每行一个整数,其中第 i 行的整数表示在必须选择第 i 个活动的
前提下,活动较少的嘉年华的活动数的最大值。

Sample Input

5 

8 2 

1 5 

5 3 

3 2 

5 3 

Sample Output

2 

2 

1 

2 

2 

2 

HINT

在没有任何限制的情况下,最优安排可以在一个嘉年华安排活动 1, 4,而在

另一个嘉年华安排活动 3, 5,活动2不安排。

1≤n≤200 0≤Si≤10^9



1≤Ti≤ 10^9

将时间离散化,令 f[i][j] 表示到时间 i 的时候,一个里面有 j 个,另一个最多有多少, o[i][j] 表示 i j 这段区间里有多少个线段。
转移就是 f[i][j]=max(f[k][j]+o[k][i]f[k][jo[k][i]])
如果强制性选一个的话,还需要设一个 g[i][j] 表示从 i 开始,一个里面有 j 个,里一个最多有多少。转移起来跟 f 数组一样。
num[i][j] 表示必须要选 i j 这一段,而且不能有区间跨过这一段的最大值。
num[i][j]=max{min(k+p+o[i][j],f[i][k]+g[j][p])}
这样暴力转移的话是 n4 的。
可以观察一下上面的那个式子,可以发现当 x 在增大的过程中, y 只有减小才可能让最大值变大。
我们就可以利用这个性质,对于每一对 i,j 都单调的维护一下 k,p 就行了。
在算答案的时候,因为 num[i][j] 中有一个限制,就是不能有区间跨过 i,j ,所以答案并不是 num[i][j] ,而是 max{num[p][q]}(p<=i,q>=j)
复杂度是 O(n3)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=410;
struct S{int l,r;}p[N];
int n,a[N],tot,f[N][N],o[N][N],g[N][N],num[N][N];
int main(){
    int i,j,k,q;
    scanf("%d",&n);
    for(i=1;i<=n;++i){
        scanf("%d%d",&p[i].l,&p[i].r);
        p[i].r+=p[i].l;
        a[++tot]=p[i].l;
        a[++tot]=p[i].r;
    }
    sort(a+1,a+tot+1);
    int size=unique(a+1,a+tot+1)-a-1;
    for(i=1;i<=n;++i){
        p[i].l=lower_bound(a+1,a+size+1,p[i].l)-a;
        p[i].r=lower_bound(a+1,a+size+1,p[i].r)-a;
        for(j=1;j<=p[i].l;++j)
            for(k=p[i].r;k<=size;++k)
                ++o[j][k];
    }
    memset(f,-10,sizeof(f));
    f[1][0]=o[1][1];
    f[1][o[1][1]]=0;
    for(i=2;i<=size;++i)
        for(j=0;j<=n;++j)
            for(k=1;k<i;++k)
                f[i][j]=max(f[i][j],max(f[k][j]+o[k][i],f[k][j-o[k][i]]));
    int ans=0;
    for(i=0;i<=n;++i) ans=max(ans,min(i,f[size][i]));
    printf("%d\n",ans); 
    memset(g,-10,sizeof(g));
    g[size][0]=o[size][size];
    g[size][o[size][size]]=0;
    for(i=size-1;i;--i)
        for(j=0;j<=n;++j)
            for(k=i+1;k<=size;++k)
                g[i][j]=max(g[i][j],max(g[k][j]+o[i][k],g[k][j-o[i][k]]));
    memset(num,-10,sizeof(num));
    for(i=1;i<=size;++i)
        for(j=i;j<=size;++j){
            k=0,q=n;
            while(1){
                int o1=min(k+1+q+o[i][j],f[i][k+1]+g[j][q]);
                int o2=min(k+q-1+o[i][j],f[i][k]+g[j][q-1]);
                if(max(o1,o2)<num[i][j]) break;
                num[i][j]=max(o1,o2);
                if(o1>o2) ++k;
                else --q;
            }
        }       
    for(i=1;i<=n;++i){
        for(ans=0,j=1;j<=p[i].l;++j)
            for(k=p[i].r;k<=size;++k)
                ans=max(ans,num[j][k]);
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/FZHvampire/article/details/51816088
今日推荐