P1973 [NOI2011] NOI 嘉年华

//URL: https://www.luogu.com.cn/problem/P1973
/*
吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办。每个嘉年华可能包含很多个活动,而每个活动只能在一个嘉年华中举办。
现在嘉年华活动的组织者小安一共收到了 nn 个活动的举办申请,其中第 ii 个活动的起始时间为 SiSi​,活动的持续时间为 TiTi​。这些活动都可以安排到任意一个嘉年华的会场,也可以不安排。
小安通过广泛的调查发现,如果某个时刻,两个嘉年华会场同时有活动在进行(不包括活动的开始瞬间和结束瞬间),那么有的选手就会纠结于到底去哪个会场,从而变得不开心。所以,为了避免这样不开心的事情发生,小安要求不能有两个活动在两个会场同时进行(同一会场内的活动可以任意进行)。
另外,可以想象,如果某一个嘉年华会场的活动太少,那么这个嘉年华的吸引力就会不足,容易导致场面冷清。所以小安希望通过合理的安排,使得活动相对较少的嘉年华的活动数量最大。
此外,有一些活动非常有意义,小安希望能举办,他希望知道,如果第 ii 个活动必须举办(可以安排在两场嘉年华中的任何一个),活动相对较少的嘉年华的活动数量的最大值
:::两个场馆不能有重叠的线段 但在一个场馆可以重叠 1.问线段数最小的 数目 最大是多少2.在必选某一线段时 线段数最小的 数目 最大是多少               

t[i][j]:[i,j]完全覆盖的数量
f[i][j]:in_pos_1-i 第一个会场举办j情况下 另一个max几个  f[0][0]=0
g[i][j]:.......i-T 第一个会场举办j情况下 另一个max几个
1.->max{min(f[T][j],j)}
f[i][j]=max(f[k][j-t[k][i]],f[k][j]+t[k][i])
2.强制选 min(x+inter[L][R]+y,f[L][x]+g[R][y]) O(N^5)
ans[L][R]=max_{L,R,x,y} min(x+inter[L][R]+y,f[L][x]+g[R][y]) O(N^4)
    f[L][x]和g[R][y]g[R][y]分别是关于xx和yy的减函数
    所以对于固定的L,RL,R, 当xx变大时,最优的yy应该变小才能使答案更好
    这样一来,将y作为一个随x增加而递减的指针即可时间复杂度为O(n3)

枚举时f[i][j<=n/2]
*/
/*
5 
8 2 
1 5 
5 3 
3 2 
5 3 

2 
2 
1 
2 
2 
2 
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>   
typedef long long ll;
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=4e2 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

int n,a[maxn],b[maxn],u[maxn],v[maxn],p[maxn],q[maxn],t;
int inter[maxn][maxn],f[maxn][maxn],g[maxn][maxn],ans[maxn],txt[maxn][maxn];

int main()
{
    ios::sync_with_stdio(false);
       cin>>n;
       for(int i=1;i<=n;i++) cin>>a[i]>>b[i],b[i]+=a[i],p[++t]=a[i],p[++t]=b[i];          
       sort(p+1,p+1+t);
       
       q[1]=1;
       for(int i=2;i<=t;i++){
           if(p[i]!=p[i-1]) q[i]=q[i-1]+1;
           else q[i]=q[i-1];
       }
   //    t=q[t];
       for(int i=1;i<=n;i++){
           for(int j=1;j<=n<<1;j++){
               if(a[i]==p[j]) u[i]=q[j];
               if(b[i]==p[j]) v[i]=q[j];
           }
       }
       t=q[t];//!!!!!!!!!!!!!!!!!!!!
       for(int i=1;i<=t;i++)
           for(int j=1;j<=t;j++)
               for(int k=1;k<=n;k++)
                   if(i<=u[k]&&v[k]<=j)
                       inter[i][j]++;
                       
       for(int i=1;i<=t;i++){
           for(int j=0;j<=n/2;j++){
               f[i][j]=-inf; if(j==0) f[i][j]=inter[1][i];
               for(int k=1;k<=i;k++){
                   f[i][j]=max(f[i][j],f[k][j]+inter[k][i]);
                   f[i][j]=max(f[i][j],f[k][max(0,j-inter[k][i])]);//j<=inter[][]is illegal ->f[k][0]
               }
           }
       }
       for(int i=t;i>=1;i--){
           for(int j=0;j<=n/2;j++){
               g[i][j]=-inf; if(j==0) g[i][j]=inter[i][t];
               for(int k=i;k<=t;k++){
                   g[i][j]=max(g[i][j],g[k][j]+inter[i][k]);//???
                   g[i][j]=max(g[i][j],g[k][max(0,j-inter[i][k])]);
               }
           }
       }
       for(int i=0;i<=n;i++)
       ans[0]=max(ans[0],min(f[t][i],i));
       
       for(int l=1;l<=t;l++)
       {
           for(int r=1;r<=t;r++)
           {
               for(int x=0;x<=inter[1][l];x++)
               {
                   for(int y=0;y<=inter[r][t];y++)
                   {
                       txt[l][r]=max(txt[l][r],min(inter[l][r]+x+y,f[l][x]+g[r][y]));    
                       if(g[r][y]<=y) break;     
                   }
                   if(f[l][x]<=x) break;
               }
               //if (inter[1][l]+inter[r][t]<ans[k]) break;
            //if (inter[l][r]>inter[1][l]+inter[r][t]) break;                                                        
        
           }
       }
       for(int i=1;i<=n;i++)
           for(int l=u[i];l>=1;l--)
               for(int r=v[i];r<=t;r++)
                   ans[i]=max(ans[i],txt[l][r]);
       
       for(int i=0;i<=n;i++) cout<<ans[i]<<'\n';
       
    return 0;
}

 

posted @ 2023-12-29 14:21  JMXZ  阅读(18)  评论(0)    收藏  举报