[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\n",ans[i]);return 0;
}
?
轉載于:https://www.cnblogs.com/Landlord-greatly/p/8144349.html
總結
以上是生活随笔為你收集整理的[NOI2011]Noi嘉年华的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 有没有一个偶像是你喜欢了10年以上的?
- 下一篇: “一日肠九回”下一句是什么