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 }

 

posted @ 2018-09-19 21:58  Ressed  阅读(426)  评论(0编辑  收藏  举报