[NOI2011]Noi嘉年华
题目描述
NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办。每个嘉年华可能包含很多个活动,而每个活动只能在一个嘉年华中举办。
现在嘉年华活动的组织者小安一共收到了 n个活动的举办申请,其中第 i 个活动的起始时间为 Si,活动的持续时间为Ti。这些活动都可以安排到任意一个嘉年华的会场,也可以不安排。
小安通过广泛的调查发现,如果某个时刻,两个嘉年华会场同时有活动在进行(不包括活动的开始瞬间和结束瞬间),那么有的选手就会纠结于到底去哪个会场,从而变得不开心。所以,为了避免这样不开心的事情发生,小安要求不能有两个活动在两个会场同时进行(同一会场内的活动可以任意进行)。
另外,可以想象,如果某一个嘉年华会场的活动太少,那么这个嘉年华的吸引力就会不足,容易导致场面冷清。所以小安希望通过合理的安排,使得活动相对较少的嘉年华的活动数量最大。
此外,有一些活动非常有意义,小安希望能举办,他希望知道,如果第i 个活动必须举办(可以安排在两场嘉年华中的任何一个),活动相对较少的嘉年华的活动数量的最大值。
输入输出格式
输入格式:
输入的第一行包含一个整数 n,表示申请的活动个数。
接下来 n 行描述所有活动,其中第 i 行包含两个整数 Si、Ti,表示第 i 个活动从时刻Si开始,持续 Ti的时间。
输出格式:
输出的第一行包含一个整数,表示在没有任何限制的情况下,活动较少的嘉年华的活动数的最大值。
接下来 n 行每行一个整数,其中第 i 行的整数表示在必须选择第 i 个活动的前提下,活动较少的嘉年华的活动数的最大值。
输入输出样例
5 8 2 1 5 5 3 3 2 5 3
2 2 1 2 2 2
说明
【样例说明】
在没有任何限制的情况下,最优安排可以在一个嘉年华安排活动1, 4,而在另一个嘉年华安排活动3, 5,活动2不安排。
如果输出格式不正确(比如输出不足n+1行),得0分;
如果输出文件第一行不正确,而且后n行至少有一行不正确,得0分;
如果输出文件第一行正确,但后n行至少有一行不正确,得4分;
如果输出文件第一行不正确,但后n行均正确,得6分;
如果输出文件中的n+1行均正确,得10分。
首先这道题每个点都给了4分的部分分.
那么先考虑40分的,就是没有限制的情况.
首先要将时间离散化.
先预处理一个东西,in[i][j]表示在时间[i,j]只内的活动的数量.这个怎么暴力怎么搞.
设f[i][j]表示时间到了i,一个选了j个活动,另一个的最大值.
那么转移就是f[i][j]=max(min(f[k][j]+in[k+1][i],f[i][j-in[k+1][i])).
就是枚举这一次选的哪些区间,是放到哪个嘉年华中.
然后40分就到手了..
考虑剩下的60分.
每次限制了一个区间必须选.
那么将状态转化一下,设num[i][j]表示必须选[i,j]内的区间,且没有其他选了的越过这个区间 的最大值.
设g[i][j]表示时间从后面到了i,一个选了j个活动,另一个的最大值.
这个和f就是反着的.
那么num[i][j]=max(min(x+y+in[i][j],f[i-1][x]+g[j+1][y])).
这样是n^4的,要考虑怎么优化.
可以看出来这个式子是具有单调性的.
当x增大时,y只有减小才能取得更大的答案.
所以就可以搞两个指针扫一遍即可,哪边大往哪边走.
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<algorithm> 7 #include<map> 8 #include<complex> 9 #include<queue> 10 #include<stack> 11 #include<cmath> 12 #include<set> 13 #include<vector> 14 #define maxn 210 15 using namespace std; 16 struct data{ 17 int l,r; 18 }k[maxn]; 19 int li[maxn*2],in[maxn*2][maxn*2],f[maxn*2][maxn],g[maxn*2][maxn],num[maxn*2][maxn*2],ans=0; 20 int main(){ 21 int n,tot=0; 22 scanf("%d",&n); 23 for(int i=1;i<=n;i++) 24 scanf("%d%d",&k[i].l,&k[i].r),k[i].r=k[i].l+k[i].r-1,li[++tot]=k[i].l,li[++tot]=k[i].r; 25 sort(li+1,li+tot+1); 26 int p=unique(li+1,li+tot+1)-li-1; 27 for(int i=1;i<=n;i++){ 28 k[i].l=lower_bound(li+1,li+p+1,k[i].l)-li; 29 k[i].r=lower_bound(li+1,li+p+1,k[i].r)-li; 30 } 31 for(int i=1;i<=p;i++) 32 for(int j=i;j<=p;j++) 33 for(int l=1;l<=n;l++) 34 if(k[l].l>=i && k[l].r<=j) in[i][j]++; 35 memset(f,-127/3,sizeof(f));memset(g,-127/3,sizeof(g)); 36 for(int i=0;i<=p+1;i++) 37 f[i][0]=0,g[i][0]=0; 38 f[1][0]=in[1][1],f[1][in[1][1]]=0; 39 g[p][0]=in[p][p],g[p][in[p][p]]=0; 40 for(int i=0;i<=p+1;i++) 41 for(int j=0;j<=n;j++) 42 for(int k=0;k<i;k++){ 43 int l=max(f[k][j]+in[k+1][i],(j-in[k+1][i]>=0)?f[k][j-in[k+1][i]]:0); 44 f[i][j]=max(f[i][j],l); 45 ans=max(ans,min(j,f[i][j])); 46 } 47 printf("%d\n",ans); 48 for(int i=p+1;i>=0;i--) 49 for(int j=0;j<=n;j++) 50 for(int k=p+1;k>i;k--){ 51 int l=max(g[k][j]+in[i][k-1],(j-in[i][k-1]>=0)?g[k][j-in[i][k-1]]:0); 52 g[i][j]=max(g[i][j],l); 53 } 54 memset(num,-127/3,sizeof(num)); 55 for(int i=0;i<=p+1;i++) 56 for(int j=i;j<=p+1;j++){ 57 int l=0,r=n; 58 while(l<=n && r>=0){ 59 int x=min(l+1+r+in[i][j],f[i-1][l+1]+g[j+1][r]); 60 int y=min(l+r-1+in[i][j],f[i-1][l]+g[j+1][r-1]); 61 //if(max(x,y)<num[i][j]) break; 62 if(x<y) r--,num[i][j]=max(num[i][j],y); 63 else l++,num[i][j]=max(num[i][j],x); 64 } 65 //num[i][j]=ans; 66 } 67 for(int i=1;i<=n;i++){ 68 ans=0; 69 for(int j=0;j<=k[i].l;j++) 70 for(int w=k[i].r;w<=p+1;w++) 71 ans=max(ans,num[j][w]); 72 printf("%d\n",ans); 73 } 74 return 0; 75 }