标签:qr int 题解 long Skip ql dp define
CDQ分治优化DP的板子题
发现式子可以整理成 \(dp[i]=max\{dp[j]+\binom{i-j}{2}\}+a[i]\ (i>j,\ a[i]>a[j])\) 的形式
于是用CDQ处理掉后面的两个限制条件,剩下的用斜率优化处理
注意CDQ套斜率优化的时候不能在一开始就把所有决策点都扔进单调队列里
需要等到一个决策点满足限制条件了再扔
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define reg register int
#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
ll a[N];
namespace force{
ll dp[N];
inline ll sum(ll k) {return k*(k+1)/2;}
void solve() {
memset(dp, 128, sizeof(dp));
a[0]=-INF; a[n+1]=INF; dp[0]=0;
for (int i=1; i<=n; ++i) {
for (int j=0; j<i; ++j) if (a[j]<=a[i]) {
dp[i]=max(dp[i], dp[j]-sum(i-j-1));
}
dp[i]+=a[i];
}
for (int i=0; i<=n; ++i) dp[n+1]=max(dp[n+1], dp[i]-sum(n-i));
printf("%lld\n", dp[n+1]);
exit(0);
}
}
namespace task1{
ll dp[N], l=1, r=0;
// struct que{double val; int pos; inline void build(double v, int p) {val=v; pos=p;}}q[N];
int q[N];
inline ll sum(ll k) {return k*(k+1)/2;}
inline double calc(ll j, ll k) {return ((2.0*dp[k]-k*k+k)-(2.0*dp[j]-j*j+j))/(1.0*j-k);}
void solve() {
memset(dp, 128, sizeof(dp));
a[0]=-INF; a[n+1]=INF; dp[0]=0;
q[++r]=0;
for (int i=1; i<=n; ++i) {
// while (l<r && a[q[l]]>=a[q[l+1]] && calc(q[l], q[l+1])>=double(2*i)) ++l;
for (int j=l; j<=r; ++j) if (a[q[j]]<=a[i]) {
dp[i]=max(dp[i], dp[q[j]]-sum(i-q[j]-1));
}
dp[i]+=a[i];
while (l<r && a[q[r-1]]>=a[q[r]] && calc(q[r-1], q[r])<double(2*i)) {/*cout<<calc(q[r-1], q[r])<<endl;*/ --r;}
q[++r]=i;
}
// cout<<"q: "; for (int i=l; i<=r; ++i) cout<<q[i]<<' '; cout<<endl;
for (int i=l; i<=r; ++i) dp[n+1]=max(dp[n+1], dp[q[i]]-sum(n-q[i]));
printf("%lld\n", dp[n+1]);
exit(0);
}
}
namespace task{
ll dp[N];
int q[N], p[N];
inline double calc(ll j, ll k) {return ((2.0*dp[k]-k*k-k)-(2.0*dp[j]-j*j-j))/(1.0*j-k);}
inline bool cmp1(int i, int j) {return a[i]<a[j];}
inline ll sum(ll k) {return k*(k+1)/2;}
void cdq(int l, int r) {
// cout<<"cdq: "<<l<<' '<<r<<endl;
if (l==r) {dp[p[l]]+=a[p[l]]; return ;}
int mid=(l+r)>>1, ql=1, qr=0;
cdq(l, mid);
sort(p+l, p+mid+1); sort(p+mid+1, p+r+1);
// cout<<"sort: "<<l<<' '<<r<<endl;
// cout<<"p: "; for (int i=l; i<=r; ++i) cout<<p[i]<<' '; cout<<endl;
// cout<<"a: "; for (int i=l; i<=r; ++i) cout<<a[p[i]]<<' '; cout<<endl;
// cout<<"q: "; for (int i=ql; i<=qr; ++i) cout<<q[i]<<' '; cout<<endl;
for (int i=mid+1,pos1=l; i<=r; ++i) {
// cout<<"calc: "<<p[i]<<' '<<q[ql]<<' '<<q[ql+1]<<' '<<calc(q[ql], q[ql+1])<<' '<<2*p[i]<<endl;
while (pos1<=mid && p[pos1]<p[i]) {
while (ql<qr && calc(q[qr-1], q[qr])>calc(q[qr], p[pos1])) --qr;
q[++qr]=p[pos1];
++pos1;
}
while (ql<qr && p[i]>q[ql+1] && calc(q[ql], q[ql+1])<2*p[i]) {
// cout<<"a: "<<a[p[i]]<<' '<<a[q[ql+1]]<<endl;
// cout<<"k: "<<q[ql]<<' '<<q[ql+1]<<' '<<calc(q[ql], q[ql+1])<<' '<<2*p[i]<<endl;
++ql;
}
// cout<<"tran: "<<p[i]<<' '<<q[ql]<<endl;
if (p[i]>q[ql]) {
dp[p[i]]=max(dp[p[i]], dp[q[ql]]-sum(p[i]-q[ql]-1));
// cout<<"tran: "<<p[i]<<' '<<q[ql]<<' '<<dp[q[ql]]-sum(p[i]-q[ql]-1)<<' '<<dp[q[ql]]<<endl;
}
}
sort(p+l, p+r+1, cmp1);
cdq(mid+1, r);
}
void solve() {
memset(dp, 128, sizeof(dp));
a[0]=-INF; a[n+1]=INF; dp[0]=INF;
for (int i=0; i<=n; ++i) p[i]=i;
sort(p, p+n+1, cmp1);
cdq(0, n);
// cout<<"dp: "; for (int i=0; i<=n; ++i) cout<<dp[i]<<' '; cout<<endl;
for (int i=0; i<=n; ++i) dp[n+1]=max(dp[n+1], dp[i]-sum(n-i));
printf("%lld\n", dp[n+1]);
exit(0);
}
}
signed main()
{
freopen("skip.in", "r", stdin);
freopen("skip.out", "w", stdout);
n=read();
for (int i=1; i<=n; ++i) a[i]=read();
// force::solve();
// task1::solve();
task::solve();
return 0;
}
标签:qr,int,题解,long,Skip,ql,dp,define 来源: https://www.cnblogs.com/narration/p/15355144.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。