题解:P9691 [GDCPC 2023] Base Station Construction
思路
First
一眼 DP。
Second
设
考虑如何转移。
可以想象转移方程的样子大概是
所以接下来的任务是对于每个
考虑什么样的
即对于所有的
所以
这样 DP 方程就结束了。
此时复杂度
Third
本题重点——单调队列优化 DP,来了!
不会单调队列的不妨看一下这个题。
然后就没有然后了。
思考单调队列过程时,现在在点
如果 q.front()<Left[i],就 q.pop()。
然后转移,最后加入
最终复杂度
Last
这时候有人就问了:所以最终状态是什么呢?
这里比较巧妙,在给定的
最终答案就是
最终有一些不可缺少的东西。
#include<bits/stdc++.h>
#define int long long
using namespace std;
bool Beginning;
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define se second
#define fi first
using PII=pair<int,int>;
using PIB=pair<int,bool>;
using PBI=pair<bool,int>;
using PBB=pair<bool,bool>;
using PDI=pair<double,int>;
using PID=pair<int,double>;
namespace Memory_Love{
int read(){ int x=0; bool flag=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') flag=0;ch=getchar();}
while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return flag? x:-x;}
void write(int x,char ch=0){if(x<0) x=-x,putchar('-');
static short s[35],top=-1; do{s[++top]=x%10;x/=10;}while(x);
while(~top) putchar(s[top--]+48); if(ch) putchar(ch);}
int gcd(int a,int b){return b==0? a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;}
} using namespace Memory_Love;
const int N=5e5+5;
int n,m;
int a[N],L[N],R[N];
namespace DP
{
int last[N],dp[N];
deque<int> q;
void init()
{
int i; a[++n]=0;
while(q.size()) q.pop_back();
for(i=1;i<=n;i++) last[i]=0;
for(i=1;i<=m;i++) last[R[i]+1]=max(last[R[i]+1],L[i]);
for(i=1;i<=n;i++) last[i]=max(last[i],last[i-1]);
}
int solve()
{
int i;
q.push_back(0);
for(i=1;i<=n;i++)
{
while(q.size() && q.front()<last[i])
q.pop_front();
dp[i]=dp[q.front()]+a[i];
while(q.size() && dp[q.back()]>dp[i])
q.pop_back();
q.push_back(i);
}
return dp[n];
}
}
int solve()
{
int i;
n=read(); for(i=1;i<=n;i++) a[i]=read();
m=read(); for(i=1;i<=m;i++) L[i]=read(),R[i]=read();
DP::init(); return DP::solve();
}
bool Ending;
signed main()
{
int T=read(); while(T--) write(solve(),'\n');
cerr<<"\nused:"<<(abs(&Ending-&Beginning)/1048576)<<"MB\n";
return 0;
}