题解:P16956 「NLOI Round1」真空剑圣

· · 题解

其他题解怎么都是 O(n) 的?那就让我来一发无脑 O(m) DP,清晰易懂,我认为难度只有黄!

首先观察一个简单的性质,这也是本做法的最难点:每一个点只被操作一次是不劣的,因为如果被操多次,除最后一次都是无意义的。

那就 DP,设 f_{i,j} 表示操作完前 i 个点,且第 i 个点在 j 时刻被操作的最大总和。转移:

f_{i,j}=\max_{k\ne j}\{f_{i-1,k}\}+y_j\\ f_{i,0}=\max_{k}\{f_{i-1,k}\}+a_i

第一条转移存在的条件是 x_j=ix_j+1=i

你可能会问:状态数不是 $O(nm)$ 的吗?\ 在所有 $m$ 种可能的 $j$ 中,每个 $j$ 只对应两个 $i$ 分别是 $x_j,x_j+1$,所以 $j$ 非零的 $f_{i,j}$ 只有 $2m$ 个,状态数为 $2m+n$ 在 $O(m)$ 级别。 $\max\{f_{n,j}\}$ 即为答案。 :::success[二分版本(不要用 map 因为会被卡常)] ```cpp #include <bits/stdc++.h> #define fi first #define se second #define mid ((l+r)>>1) #define bmid ((l+r+1)>>1) #define pb push_back #define eb emplace_back #define fswap(a,b) ((a)^=(b)^=(a)^=(b)) using namespace std; using ll= long long; #ifndef ONLINE_JUDGE template <typename tp> void _debug(const tp& t) {cerr<<t<<'\n';} template <typename tp,typename... args> void _debug(const tp& t, const args&... rest) {cerr<<t<<' ';_debug(rest...);} #define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__) #else #define debug(...) 0 #endif #define int ll const int N=200005,H=N<<2,inf=1000000000,mod=1000000007; vector<pair<int,int> > vec[N]; vector<pair<int,int> > f[N],pre[N],suf[N]; int n,m,a[N]; signed main() { cin.tie(nullptr)->sync_with_stdio(false); cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int x,y,i=1;i<=m;i++) { cin>>x>>y; vec[x].eb(i,y); vec[x+1].eb(i,y); } f[0].eb(0,0),pre[0].eb(0,0),suf[0].eb(0,0); for(int i=1;i<=n;i++) { f[i].eb(0,pre[i-1].back().se+a[i]); for(auto& t: vec[i]) { const int j=t.fi,x=t.se; auto p=lower_bound(pre[i-1].begin(),pre[i-1].end(),make_pair(j,0ll)); int tm=0; if(p!=pre[i-1].begin()) tm=max(tm,prev(p)->se+x); p=upper_bound(suf[i-1].begin(),suf[i-1].end(),make_pair(j,inf)); if(p!=suf[i-1].end()) tm=max(tm,p->se+x); f[i].eb(j,tm); } for(auto t: f[i]) debug(i,t.fi,t.se); int last=0; vector<pair<int,int> > ve; for(auto t: f[i]) { ve.pb(t); last=max(last,t.se); pre[i].eb(t.fi,last); } last=0; reverse(ve.begin(),ve.end()); for(auto t: ve) { last=max(last,t.se); suf[i].eb(t.fi,last); } reverse(suf[i].begin(),suf[i].end()); } cout<<pre[n].back().se; return 0; } ``` ::: :::success[双指针版本] ```cpp #include <bits/stdc++.h> #define fi first #define se second #define mid ((l+r)>>1) #define bmid ((l+r+1)>>1) #define pb push_back #define eb emplace_back #define fswap(a,b) ((a)^=(b)^=(a)^=(b)) using namespace std; using ll= long long; #ifndef ONLINE_JUDGE template <typename tp> void _debug(const tp& t) {cerr<<t<<'\n';} template <typename tp,typename... args> void _debug(const tp& t, const args&... rest) {cerr<<t<<' ';_debug(rest...);} #define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__) #else #define debug(...) 0 #endif #define int ll const int N=200005,H=N<<2,inf=1000000000,mod=1000000007; vector<pair<int,int> > vec[N]; vector<pair<int,int> > f[N],pre[N],suf[N]; int n,m,a[N]; signed main() { cin.tie(nullptr)->sync_with_stdio(false); cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int x,y,i=1;i<=m;i++) { cin>>x>>y; vec[x].eb(i,y); vec[x+1].eb(i,y); } f[0].eb(0,0),pre[0].eb(0,0),suf[0].eb(0,0); for(int i=1;i<=n;i++) { f[i].eb(0,pre[i-1].back().se+a[i]); int p1=0,p2=0; for(auto& t: vec[i]) { const int j=t.fi,x=t.se; while(p1+1<f[i-1].size()&&f[i-1][p1+1].fi<j) p1++; while(p2<f[i-1].size()&&f[i-1][p2].fi<=j) p2++; int tm=0; tm=max(tm,pre[i-1][p1].se+x); if(p2!=suf[i-1].size()) tm=max(tm,suf[i-1][p2].se+x); f[i].eb(j,tm); } for(auto t: f[i]) debug(i,t.fi,t.se); int last=0; vector<pair<int,int> > ve; for(auto t: f[i]) { ve.pb(t); last=max(last,t.se); pre[i].eb(t.fi,last); } last=0; reverse(ve.begin(),ve.end()); for(auto t: ve) { last=max(last,t.se); suf[i].eb(t.fi,last); } reverse(suf[i].begin(),suf[i].end()); } cout<<pre[n].back().se; return 0; } ``` :::