luogu4182 [USACO18JAN] Lifeguards P (单调队列优化dp)
显然可以先把被覆盖掉的区间去掉,然后排个序,左、右端点就都是单调的
设f[i][j]表示前i个区间中删掉j个,而且钦定i不能删的最大覆盖长度
(如果不钦定,就要有一个删掉的状态,那我无法确定前面的到底到哪是没删的)
那么有$f[i][j]=max\{f[k][j-(i-k-1)]+R[i]-max(L[i],R[k])\} ,k<i$
稍微理解一下:k是我们下一次钦定要选的,中间的区间就都扔掉,然后有两种情况:k和i重合或不重合,那新增加一个i区间多覆盖的长度就要从i的左端点和k的右端点挑一个较大的减一减
复杂度$O(nk^2)$,显然需要优化
现在我们考虑f[i][j]到底能从哪些状态转移过来
设能转移到f[i][j]的状态是f[k][l],然后根据上面的式子,我们发现k-l=i-j-1 ,就是说当i和j固定时,l只和k有关
而且在这些状态中,对于一些比较小的k,它是和i区间不相交的,也就是它的贡献只和它的f有关
那我们就在这些k中先取一个最大的f[k][l],然后加上i区间的长度,作为一个可选的答案
对于剩下那些k,它的贡献就变成了f[k][l]-R[k],也是和i无关的
那我们就可以用一些单调队列,每个单调队列q[i]维护k-l=i的k,l的最大贡献
我们每次求f[i][j]的时候,先把q[i-j-1]中队头表示的区间不与i相交的踢出去,然后这个要求的最大值就是队头,然后再把f[i][j]加到q[i-j]里就完事了
为了方便统计答案,我们增加一个从1e9到1e9的区间,然后钦定它要选就可以了
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define ll long long 4 using namespace std; 5 const int maxn=100010,maxk=110; 6 7 inline ll rd(){ 8 ll x=0;char c=getchar();int neg=1; 9 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 10 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 11 return x*neg; 12 } 13 14 struct POS{ 15 int l,r; 16 }pos[maxn],p[maxn]; 17 int N,K; 18 int f[maxn][maxk]; 19 int que[maxn][maxk],qh[maxn],qt[maxn],ma[maxn]; 20 21 inline bool cmp(POS a,POS b){ 22 return a.l==b.l?a.r>b.r:a.l<b.l; 23 } 24 25 int main(){ 26 int i,j,k; 27 //freopen("testdata.in","r",stdin); 28 N=rd(),K=rd(); 29 for(i=1;i<=N;i++){ 30 pos[i].l=rd(),pos[i].r=rd(); 31 }sort(pos+1,pos+N+1,cmp); 32 int mm=0; 33 for(i=1,j=0;i<=N;i++){ 34 if(mm<pos[i].r) p[++j]=pos[i],mm=pos[i].r; 35 }K-=N-j;N=j; 36 if(K<=0){ 37 int ans=0; 38 for(i=1;i<=N;i++){ 39 ans+=max(0,p[i].r-max(p[i-1].r,p[i].l)); 40 }printf("%d\n",ans); 41 }else{ 42 p[N+1].l=1e9,p[N+1].r=1e9;N++; 43 for(i=1;i<=N;i++){ 44 for(j=0;j<=min(i-1,K);j++){ 45 int ii=i-j-1; 46 while(qh[ii]<qt[ii]&&p[que[ii][qh[ii]]].r<=p[i].l){ 47 ma[ii]=max(ma[ii],f[que[ii][qh[ii]]][que[ii][qh[ii]]-ii]);qh[ii]++; 48 }int hh=que[ii][qh[ii]]; 49 f[i][j]=max(ma[ii]+p[i].r-p[i].l,f[hh][hh-ii]+p[i].r-max(p[hh].r,p[i].l)); 50 ii=i-j;int qq=que[ii][qt[ii]]; 51 while(qh[ii]<qt[ii]&&f[qq][qq-ii]-p[qq].r<=f[i][j]-p[i].r){ 52 qt[ii]--;qq=que[ii][qt[ii]]; 53 }que[ii][++qt[ii]]=i;if(!qh[ii]) qh[ii]++; 54 } 55 } 56 printf("%d\n",f[N][K]); 57 } 58 return 0; 59 }