[海军国际项目办公室]铺设道路
铺设道路
题目


题解
首先,我们有一个对于区间加减的很经典的转化,通过差分的转化使得我们的区间加减变成单点的改变。
我们定义
b
i
=
d
i
−
d
i
−
1
b_i=d_{i}-d_{i-1}
bi=di−di−1,那么我们对区间
(
l
,
r
)
(l,r)
(l,r)进行操作相当于让
b
l
−
1
b_{l}-1
bl−1,
b
r
+
1
+
1
b_{r+1}+1
br+1+1,其代价为
(
r
−
l
+
1
)
2
(r-l+1)^2
(r−l+1)2。
显然,
d
i
=
∑
j
=
1
i
b
j
d_{i}=\sum_{j=1}^{i}b_{j}
di=∑j=1ibj,也就是说在合法情况下,我们的
d
d
d的前缀和应该是始终不小于
0
0
0的。
由于要让总的操作次数最小,我们肯定只会让
b
>
0
b>0
b>0的
b
l
−
1
b_{l}-1
bl−1,让
b
r
+
1
<
0
b_{r+1}<0
br+1<0的
b
r
+
1
+
1
b_{r+1}+1
br+1+1。
显然,既然它的前缀和是始终大于
0
0
0的,所以我们是一定找得到这样的匹配的
(
l
,
r
)
(l,r)
(l,r)。
而我们最后的到的序列有是一个全
0
0
0的序列,而我们有只会让
d
d
d减小,所以我们在过程中一定是保证
d
d
d全部大于
0
0
0,即所有操作都是合法的。
最小操作次数显然是
∑
max
(
b
i
,
0
)
\sum \max(b_{i},0)
∑max(bi,0)。
我们关键是要怎么匹配
b
b
b使得我们最后的代价和最大于最小。
由于我们的代价是平方项,而它们一次方状况下的总和是固定的,所以我们肯定要让它们长的段越多权值肯定越大,较长的段越小权值肯定越小。
所以我们肯定是对于
b
i
<
0
b_{i}<0
bi<0的
b
i
b_{i}
bi匹配离他最近的
b
j
>
0
b_{j}>0
bj>0的
b
j
b_{j}
bj,将更远的留给后面使得我们的总贡献越大。
而将其匹配最远的
b
j
<
0
b_{j}<0
bj<0的
b
j
b_{j}
bj可以使得所有的长度都较短,使得总贡献较小。
该匹配过程显然可以通过队列进行维护。
时间复杂度 O ( n ) O\left(n\right) O(n)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 300005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x<<'\n'
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
char gc(){static char buf[10000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,10000000,stdin),p1==p2)?EOF:*p1++;}
//#define getchar gc
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,d[MAXN],b[MAXN],ansmax,ansmin;LL ans;
deque<pii>q;
signed main(){
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
read(n);for(int i=1;i<=n;i++)read(d[i]);
for(int i=1;i<=n+1;i++)b[i]=d[i]-d[i-1],ans+=1ll*max(b[i],0);
for(int i=1;i<=n+1;i++){
if(b[i]>0)q.push_back(mkpr(i,b[i]));
else while(b[i]<0){
pii t=q.front();q.pop_front();
int tmp=min(-b[i],t.sec);b[i]+=tmp;t.sec-=tmp;
Add(ansmin,1ll*(i-t.fir)*(i-t.fir)%mo*tmp%mo,mo);
if(t.sec)q.push_front(t);
}
}
while(!q.empty())q.pop_back();
for(int i=1;i<=n+1;i++)b[i]=d[i]-d[i-1];
for(int i=1;i<=n+1;i++){
if(b[i]>0)q.push_back(mkpr(i,b[i]));
else while(b[i]<0){
pii t=q.back();q.pop_back();
int tmp=min(-b[i],t.sec);b[i]+=tmp;t.sec-=tmp;
Add(ansmax,1ll*(i-t.fir)*(i-t.fir)%mo*tmp%mo,mo);
if(t.sec)q.push_back(t);
}
}
printf("%lld\n%d\n%d\n",ans,ansmax,ansmin);
return 0;
}

浙公网安备 33010602011771号