NOIP 模擬 $83\; \rm 鋪設道路$
阿新 • • 發佈:2021-10-26
題解
題解 \(by\;zj\varphi\)
算次數不難,重點在於如何求最大最小值。
對於一個序列,想要用最少的步數把序列抹平,一定是先把不同高度向下抹成同一高度,再統一減少。
對於最小值,每次儘量抹平最左邊的值,而最大值,儘量抹平離得近的。
原因就是,抹離得遠的每次較平均,而抹離得近的,會使最後區間長越來越大,導致最後答案最大。
Code
#include<bits/stdc++.h> #define ri signed #define pd(i) ++i #define bq(i) --i #define func(x) std::function<x> namespace IO{ char buf[1<<21],*p1=buf,*p2=buf; #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++ #define debug1(x) std::cerr << #x"=" << x << ' ' #define debug2(x) std::cerr << #x"=" << x << std::endl #define Debug(x) assert(x) struct nanfeng_stream{ template<typename T>inline nanfeng_stream &operator>>(T &x) { bool f=false;x=0;char ch=gc(); while(!isdigit(ch)) f|=ch=='-',ch=gc(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc(); return x=f?-x:x,*this; } }cin; } using IO::cin; namespace nanfeng{ #define FI FILE *IN #define FO FILE *OUT template<typename T>inline T cmax(T x,T y) {return x>y?x:y;} template<typename T>inline T cmin(T x,T y) {return x>y?y:x;} using ll=long long; static const int N=3e5+7,MOD=1e9+7; int a[N],que[N],pos=1,n; ll w[N],ans,ans1,ans2; inline int main() { FI=freopen("road.in","r",stdin); FO=freopen("road.out","w",stdout); cin >> n; for (ri i(1);i<=n;pd(i)) cin >> a[i]; for (ri i(1);i<=n+1;pd(i)) if (a[i]>a[i-1]) w[i]=a[i]-a[i-1],ans+=w[i]; else if (a[i]<a[i-1]) { int nw=a[i-1]-a[i]; while(nw) if (w[pos]<=nw) { ans2+=w[pos]*(i-pos)*(i-pos)%MOD; nw-=w[pos++]; } else { ans2+=1ll*nw*(i-pos)*(i-pos)%MOD; w[pos]-=nw,nw=0; } } memset(w,0,sizeof(w)); pos=0; for (ri i(1);i<=n+1;pd(i)) if (a[i]>a[i-1]) { w[++pos]=a[i]-a[i-1]; que[pos]=i; } else { int nw=a[i-1]-a[i]; while(nw) if (w[pos]<=nw) { ans1+=w[pos]*(i-que[pos])*(i-que[pos])%MOD; nw-=w[pos--]; } else { ans1+=1ll*nw*(i-que[pos])*(i-que[pos])%MOD; w[pos]-=nw,nw=0; } } printf("%lld\n%lld\n%lld\n",ans,ans1%MOD,ans2%MOD); return 0; } } int main() {return nanfeng::main();}