【题解】
这道题不是按"第i个活动在哪个嘉年华举办"来进行决策的,而是利用题目"嘉年华A与B的活动时间无交叉"的性质,在离散化时间的基础上表示状态:
pre[i][j]表示:时间[1,i]中有j个活动在嘉年华A举办时,嘉年华B举办的最大活动数所以,用<延迟更新是错误的
【代码】
#include<stdio.h> #include<stdlib.h> #define INF 1000000 int num[405][405]={0},ans[405][405]={0},pre[405][205]={0},suc[405][205]={0},s[205]={0},t[205]={0},a[405]={0},c[405]={0}; int min(int a,int b) { if(a<b) return a; return b; } int max(int a,int b) { if(a>b) return a; return b; } void jh(int* a,int* b) { int t=*a; *a=*b; *b=t; } void kp(int low,int high)//快排 { int i=low,j=high,mid=a[(i+j)/2]; while(i<j) { while(a[i]<mid) i++; while(a[j]>mid) j--; if(i<=j) { jh(&a[i],&a[j]); jh(&c[i],&c[j]); i++; j--; } } if(j>low) kp(low,j); if(i<high) kp(i,high); } int main() { int n,T=0,i,j,k,x,y,Ans=0; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&s[i],&t[i]); t[i]+=s[i]; a[2*i-1]=s[i]; a[2*i]=t[i]; } for(i=1;i<=2*n;i++) c[i]=i; kp(1,2*n); for(i=1;i<=2*n;i++) { if(i==1||a[i]!=a[i-1]) T++;//离散化后时间从1开始 if(c[i]%2==1) s[c[i]/2+1]=T; else t[c[i]/2]=T; } for(i=1;i<=n;i++) for(j=1;j<=s[i];j++) for(k=t[i];k<=T;k++) num[j][k]++; for(i=1;i<=T;i++) for(j=1;j<=n;j++) pre[i][j]=suc[i][j]=-INF; for(i=1;i<=T;i++) for(j=0;j<=n;j++) for(k=1;k<i;k++) { pre[i][j]=max(pre[i][j],pre[k][j]+num[k][i]); if(j>=num[k][i]) pre[i][j]=max(pre[i][j],pre[k][j-num[k][i]]); } for(i=T;i>=1;i--) for(j=0;j<=n;j++) for(k=i+1;k<=T;k++) { suc[i][j]=max(suc[i][j],suc[k][j]+num[i][k]); if(j>=num[i][k])suc[i][j]=max(suc[i][j],suc[k][j-num[i][k]]); } for(i=0;i<=n;i++) Ans=max(Ans,min(i,pre[T][i])); printf("%d\n",Ans); for(i=1;i<T;i++) for(j=i+1;j<=T;j++) { y=num[j][T]; for(x=0;x<=num[1][i];x++) { while(y>0&&min(x+y+num[i][j],pre[i][x]+suc[j][y])<=min(x+y-1+num[i][j],pre[i][x]+suc[j][y-1])) y--; ans[i][j]=max(ans[i][j],min(x+y+num[i][j],pre[i][x]+suc[j][y])); } } for(i=1;i<=n;i++) { Ans=0; for(j=1;j<=s[i];j++) for(k=t[i];k<=T;k++) Ans=max(Ans,ans[j][k]); printf("%d\n",Ans); } return 0; }