【题解 P8476】 惊蛰
「GLR-R3」惊蛰
题目背景
「微雨众卉新,一雷惊蛰始」
中午,休息室,阿绫肩膀上。
“我有一个愿望,参加全国音乐祭,获奖,和阿绫一起,摆脱这训练的苦海。”
“为热爱而到来,为抽身而努力……吗”。
正午的阳光渗过窗帘,抚上困倦的人儿的脸颊。天依的左手悄悄搭上阿绫怀里的吉他,
“铮——”
蛰虫被雷声唤醒,没人向他们保证雨的降临。
惊蛰 「我愿把岁月磨成望镜寻遍这星空 将微光聚焦手心紧紧握住不放松」
题目描述
比赛临近,各式测试也丰富了起来,作为天依他们的专业分析师,你的工作是统计分析队员们表现情况——总之,某领导要来慰问,所以你被要求修改出一份令人赏心悦目的分析报告。
在已有的 \(n\) 次测试中,对于某位特定的选手,他在第 \(i\) 次测试的波动值是非负整数 \(a_i\)。波动值越小表示选手在测试中的心态和发挥越稳定,所以你需要“略微调整”波动值序列 \(\{a_n\}\),得到另一个非负整数序列 \(\{b_n\}\)。不过,做人不能昧良心,但报告又必须好看,所以 \(\{b_n\}\) 有如下要求:
-
\(\{b_n\}\) 单调不递增,选手越来越厉害嘛;
-
对于每个 \(i\),如果 \(b_i<a_i\),老师会不高兴,所以你需要花费 \(C\) 单位的精力说服老师(其中 \(C\) 为给定常数);
-
对于每个 \(i\),如果 \(a_i\le b_i\),选手会不高兴,而且可能很不高兴,所以你需要花费 \(b_i-a_i\) 单位的精力安慰选手。
你希望在满足条件的情况下,最小化花费的精力之和。作为成熟的信竞选手,你自然需要自己动手,求出这一最小化的结果。
形式化题意
给定非负整数序列 \(\{a_n\}\),定义函数 \(f(x,y)\) 为
其中 \(C\) 是给定常数。请构造一个不增非负整数序列 \(\{b_n\}\),最小化
你仅需输出这一最小化的结果。
输入格式
第一行两个整数,表示序列长度 \(n\) 和给定常数 \(C\)。
接下来一行表示序列 \(\{a_n\}\) 。
输出格式
输出一行一个整数,表示最小化的结果。
样例 #1
样例输入 #1
3 3
4 5 2
样例输出 #1
1
样例 #2
样例输入 #2
10 5
12 17 20 2 0 1 13 6 10 1
样例输出 #2
26
提示
样例 #1 解释
构造 \(\{b_n\}=\{5,5,2\}\),可见:
样例 #2 解释
构造 \(\{b_n\}=\{12,11,4,2,1,1,1,1,1,1\}\),可以得到答案。
数据规模与约定
本题采用 Subtask 的计分方式。
设 \(V\) 为序列 \(\{a_n\}\) 中元素以及常数 \(C\) 的值域。
对于 \(100\%\) 的数据,\(1\le n\le10^6\),\(V\subseteq[0,10^9]\)。
对于不同的子任务,作如下约定:
子任务编号 | \(n\) | \(V\) | 特殊性质 | 子任务分值 |
---|---|---|---|---|
\(1\) | \(\le10^3\) | \(\subseteq[0,10^9]\) | 无 | \(25\) |
\(2\) | \(\le10^5\) | \(\subseteq[0,10^2]\) | 无 | \(15\) |
\(3\) | \(\le10^6\) | \(\subseteq[0,10^9]\) | A | \(5\) |
\(4\) | \(\le10^6\) | \(\subseteq[0,10^9]\) | B | \(15\) |
\(5\) | \(\le10^5\) | \(\subseteq[0,10^9]\) | 无 | \(20\) |
\(6\) | \(\le10^6\) | \(\subseteq[0,10^9]\) | 无 | \(20\) |
- 特殊性质 A:对于常数 \(C\) ,满足 \(C = 0\)。
- 特殊性质 B:对于序列 \(\{a_n\}\) ,满足元素单调递增。
解题思路
先考虑拿部分分。
看到这种题我们就可以考虑 \(DP\) ,设 \(f_{i,j}\) 为做到第 \(i\) 次测试的 \(b_i\) 为 \(j\) ,那么有
很明显,关于 \(a_i\) 我们是可以离散化的,所以 \(d\) 变成
\(t_i\) 即使变化后每一位对应的原权值。
这样只能过 Subtask 1 ,考虑优化。
首先,每一个 \(f_{i,j}\) 只跟前一个 \(f_{i-1,j}\) 有关,所以我们可以做成维护后缀 \(min\) 后再加上 \(d_{i,j}\) 。
由于有后缀 \(min\) ,所以 \(f\) 再未加上 \(d\) 是必定单调不递减,那 \(d\) 有什么单调性规律呢?
容易发现,对于 \(j<a_i\) 的部分,\(f\) 加上后必定是单调的,而 \(j \ge a_i\) 的部分,\(f\) 加上后此部分也是单调的。
所以,整个 \(f\) 在加上 \(d\) 后会分成两段单增不递减的区间,每次我们都需要对 \(f\) 做后缀 \(min\) ,给一个区间加上一个数,给一个区间加上一个递增序列,最后求最小值。
我们就可以把这个 \(DP\) 做到线段树上了,每次区间推平或区间加上一个数或区间加上一个递增序列,同时线段树二分找需推平的位置,同时维护区间最小。
时间复杂度 \(O(nlogn)\)
Code
#include<bits/stdc++.h>
using namespace std;
long long n,a[1000005],b[1000005],m,f[4000005],d1[4000005],d2[4000005],d3[4000005],f1[4000005];
set<long long> l;
map<long long,long long> p;
void galaxy1(long long x,long long l,long long r,long long v)
{
if(v==-1)return;
f[x]=f1[x]=v;
d1[x]=v;
d2[x]=d3[x]=0;
return;
}
void galaxy2(long long x,long long l,long long r,long long v)
{
f[x]+=v;
f1[x]+=v;
d2[x]+=v;
return;
}
void galaxy3(long long x,long long l,long long r,long long v)
{
f[x]+=b[l]*v;
f1[x]+=b[r]*v;
d3[x]+=v;
return;
}
void pushdown(long long x,long long l,long long r)
{
long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
if(d1[x]!=-1)galaxy1(lc,l,mid,d1[x]),galaxy1(rc,mid+1,r,d1[x]),d1[x]=-1;
if(d2[x]!=0)galaxy2(lc,l,mid,d2[x]),galaxy2(rc,mid+1,r,d2[x]),d2[x]=0;
if(d3[x]!=0)galaxy3(lc,l,mid,d3[x]),galaxy3(rc,mid+1,r,d3[x]),d3[x]=0;
return;
}
void dijah1(long long x,long long l,long long r,long long ql,long long qr,long long v)
{
if(ql<=l&&r<=qr)
{
galaxy1(x,l,r,v);
return;
}
pushdown(x,l,r);
long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
if(ql<=mid)dijah1(lc,l,mid,ql,qr,v);
if(qr>mid)dijah1(rc,mid+1,r,ql,qr,v);
f[x]=min(f[lc],f[rc]);
f1[x]=max(f1[lc],f1[rc]);
return;
}
void dijah2(long long x,long long l,long long r,long long ql,long long qr,long long v)
{
if(ql<=l&&r<=qr)
{
galaxy2(x,l,r,v);
return;
}
pushdown(x,l,r);
long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
if(ql<=mid)dijah2(lc,l,mid,ql,qr,v);
if(qr>mid)dijah2(rc,mid+1,r,ql,qr,v);
f[x]=min(f[lc],f[rc]);
f1[x]=max(f1[lc],f1[rc]);
return;
}
void dijah3(long long x,long long l,long long r,long long ql,long long qr,long long v)
{
if(ql<=l&&r<=qr)
{
galaxy3(x,l,r,v);
return;
}
pushdown(x,l,r);
long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
if(ql<=mid)dijah3(lc,l,mid,ql,qr,v);
if(qr>mid)dijah3(rc,mid+1,r,ql,qr,v);
f[x]=min(f[lc],f[rc]);
f1[x]=max(f1[lc],f1[rc]);
return;
}
long long gaia1(long long x,long long l,long long r,long long ql,long long qr)
{
if(ql<=l&&r<=qr)return f[x];
pushdown(x,l,r);
long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1,h=1e15+5;
if(ql<=mid)h=gaia1(lc,l,mid,ql,qr);
if(qr>mid)h=min(h,gaia1(rc,mid+1,r,ql,qr));
return h;
}
long long gaia2(long long x,long long l,long long r,long long ql,long long qr,long long v)
{
if(f[x]>=v)return l;
if(l==r)return -1;
long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1,h;
pushdown(x,l,r);
if(qr<=mid)return gaia2(lc,l,mid,ql,qr,v);
if(ql>mid)return gaia2(rc,mid+1,r,ql,qr,v);
if(f[rc]<v)return gaia2(rc,mid+1,r,ql,qr,v);
h=gaia2(lc,l,mid,ql,qr,v);
if(h==-1)return gaia2(rc,mid+1,r,ql,qr,v);
return h;
}
int main()
{
long long x,y;
memset(d1,-1,sizeof(d1));
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),l.insert(a[i]);
long long g=0;
set<long long>::iterator q=l.begin();
for(;q!=l.end();q++)
{
p[*q]=++g;
b[g]=*q;
}
for(int i=1;i<=n;i++)a[i]=p[a[i]];
if(a[1]!=1)dijah1(1,1,g,1,a[1]-1,m);
dijah3(1,1,g,a[1],g,1);
dijah2(1,1,g,a[1],g,-b[a[1]]);
for(int i=2;i<=n;i++)
{
y=gaia1(1,1,g,a[i-1],a[i-1]);
if(a[i-1]!=1)
{
x=gaia2(1,1,g,1,a[i-1]-1,y);
if(x!=-1)dijah1(1,1,g,x,a[i-1]-1,y);
}
if(a[i]!=1)dijah2(1,1,g,1,a[i]-1,m);
dijah3(1,1,g,a[i],g,1);
dijah2(1,1,g,a[i],g,-b[a[i]]);
}
printf("%lld",gaia1(1,1,g,1,g));
return 0;
}