题意:给你n个集合,每个集合有L到R这些种类的邮票,让你选择其中的K个集合,使得最后选择的邮票种类尽可能多,N,L,R都<=2000
题解:容易乱想到网络流,可是再细想一下就会发现处理不了这种模型的
然后看数据范围,想到dp,定义状态f[i][j]表示前i个集合选j个的最多种类,
我们发现这需要N^3,因为每次除了枚举i,j还要枚举一个q,来记录新的一个集合是从上次的哪一个集合拓展覆盖来的
苦思不得其解,看全场都a了,终于在最后1h改了状态(打的当然是重现赛)
我们发现L,R也只有2000啊,刚刚那种定义如果可行,L,R不就离散一下,没必要说这个了啊
所以又定义f[i][j],表示1-i的种类,用了j个集合的最好方案,对于每个位置i,我们先预处理up数组,覆盖i的区间最右能延伸到哪里
转移就是f[i][j+1]=max(f[i-1][j+1]f,[i][j+1]) if (up[i]) f[up[i]][j+1]=max (f[up[i]][j+1],f[i-1][j]+len); len 就是等于up[i]-i+1;
1 #include<bits/stdc++.h> 2 #define N 2005 3 using namespace std; 4 int f[N][N],up[N],T,t=1,n,m,k; 5 int main() 6 { 7 cin>>T; 8 while (T--) 9 { 10 scanf("%d%d%d",&n,&m,&k); 11 memset(up,0,sizeof up); 12 memset(f,0,sizeof f); 13 for(int i=1,x,y;i<=m;i++) 14 { 15 scanf("%d%d",&x,&y); 16 for(int j=x;j<=y;j++) up[j]=max(up[j],y); 17 } 18 for(int i=1;i<=n;i++) 19 for(int j=0;j<k;j++) 20 { 21 f[i][j+1]=max(f[i][j+1],f[i-1][j+1]); 22 if (up[i]) f[up[i]][j+1]=max(f[up[i]][j+1],f[i-1][j]+up[i]-i+1); 23 } 24 printf("Case #%d: %d ",t++,f[n][k]); 25 } 26 return 0; 27 }