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; }