cogs 1377. [NOI2011] NOI嘉年华 (dp

题意:给你n个活动的起止时间,要你从中选一些活动在2个会场安排(不能有两个活动在两个会场同时进行),使活动较少的会场活动数最大,以及在某个活动必须选择的前提下,求该答案。

思路:由于n很小,时间很大,先将时间离散化,num[l][r]表示全部在[l,r]内的活动个数,pre[i][j]表示前i的时间内给一边j个另一边最多有几个,则用1<=k<=i更新pre[i][j]=max(pre[k][j]+num[k][j],pre[k][j-num[k][i]]),第一问答案是min(pre[time][k],k)中的最大值

第二问,相当于一段区间s[i],t[i]必选,对于l<=s[i],r>=t[i],算出f[l][r] = min(x+y,pre[l][x]+num[l][r]+suf[r][y])中的最大值,x+y关于x,y单增,pre[l][x]+num[l][r]+suf[r][y]关于x,y单减,x,y不会同时变大或变小,所以从小到大枚举x时,y从大到小...

 1 #include<bits/stdc++.h>
 2 #define fo(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout);
 3 using namespace std;
 4 inline int read(){
 5     char ch=getchar();
 6     int res=0,f=1;
 7     while(!isdigit(ch))f^=(ch=='-'),ch=getchar();
 8     while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
 9     return res*f;
10 }
11 const int N=405;
12 int n,s[N],t[N],a[N],cnt,pre[N][N],suf[N][N],f[N][N],num[N][N];
13 inline void chemx(int &a,int b){
14     a=a>b?a:b;
15 }
16 inline void chemn(int &a,int b){
17     a=a>b?b:a;
18 }
19 #define calc(a,b) (min((a+b),(pre[l][a]+num[l][r]+suf[r][b])))
20 int main(){
21     fo("noi2011_show");
22     n=read();
23     for(int i=1;i<=n;i++)s[i]=read(),a[++cnt]=s[i],t[i]=read()+s[i],a[++cnt]=t[i];
24     sort(a+1,a+cnt+1);
25     cnt=unique(a+1,a+cnt+1)-a-1;
26     for(int i=1;i<=n;i++){
27         s[i]=lower_bound(a+1,a+cnt+1,s[i])-a;
28         t[i]=lower_bound(a+1,a+cnt+1,t[i])-a;
29         for(int l=1;l<=s[i];l++)
30             for(int r=t[i];r<=cnt;r++)num[l][r]++;
31     }
32     for(int i=1;i<=cnt;i++)
33         for(int j=1;j<=n;j++)pre[i][j]=suf[i][j]=-1e9;
34     for(int i=1;i<=cnt;i++)
35         for(int j=0;j<=num[1][i];j++)
36             for(int k=1;k<=i;k++){
37                 chemx(pre[i][j],pre[k][j]+num[k][i]);
38                 if(j>=num[k][i])chemx(pre[i][j],pre[k][j-num[k][i]]);
39             }
40     for(int i=cnt;i;i--)
41         for(int j=0;j<=num[i][cnt];j++)
42             for(int k=cnt;k>=i;k--){
43                 chemx(suf[i][j],suf[k][j]+num[i][k]);
44                 if(j>=num[i][k])chemx(suf[i][j],max(suf[k][j]+num[i][k],suf[k][j-num[i][k]]));
45             }
46     for(int l=1;l<=cnt;l++){
47         for(int r=l;r<=cnt;r++){
48             for(int x=0,y=num[r][cnt];x<=num[1][l];x++){
49                 while(y&&calc(x,y)<=calc(x,y-1))y--;
50                 chemx(f[l][r],calc(x,y));
51             }
52         }
53     }
54     int ans=0;
55     for(int i=1;i<=cnt;i++)for(int j=1;j<=num[1][i];j++)chemx(ans,min(pre[i][j],j));
56     cout<<ans<<'\n';
57     for(int i=1;i<=n;i++){
58         int res=0;
59         for(int l=s[i];l;l--)
60             for(int r=t[i];r<=cnt;r++)
61             chemx(res,f[l][r]);
62         cout<<res<<'\n';
63     }
64 }
View Code

猜你喜欢

转载自www.cnblogs.com/wzgg/p/11396590.html