https://namomo.top:8081/contest/2/problem/C
妙啊,學到許多
首先最大的很好想,就是要儘可能長即可,那麼就用單調棧處理出每個值作爲最小值統治的區間,然後用線段樹維護這個位置還剩多少個需要減就行了。。。其實這個就是我當時坐積木大賽的貪心做法,儘可能長
最小從羣友那裏學到了,把整個序列差分,那麼我要讓一段區間減1,就相當於在差分數組上左邊+1,右邊-1,那麼對於差分數組中每個正數,都要找負數把它抵消掉,爲了要平方最小,那麼找最近的就好了,把負數座標反着用個棧維護,對每個正數找最近的負數去抵消就行了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=5e5+10;
const int mod=1e9+7;
int n,m,cas,k,cnt,tot,ans,top;
int a[maxl],b[maxl],s[maxl],l[maxl],r[maxl];
struct nod
{
int val,id;
}c[maxl];
bool in[maxl];
ll ansmi,ansmx;
struct node
{
int l,r,tag,val;
}tree[maxl<<2];
inline bool cmp(const nod &a,const nod &b)
{
if(a.val==b.val)
return a.id<b.id;
return a.val<b.val;
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]),b[i]=a[i]-a[i-1];
c[i]=nod{a[i],i};
}
b[n+1]=-a[n];
sort(c+1,c+1+n,cmp);
}
inline ll sqr(ll x)
{
return x*x%mod;
}
inline void build(int k,int l,int r)
{
tree[k].l=l;tree[k].r=r;
if(l==r)
{
tree[k].val=a[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline void gank(int k)
{
if(tree[k].l==tree[k].r)
return;
int x=tree[k].tag;
tree[k<<1].val-=x;tree[k<<1].tag+=x;
tree[k<<1|1].val-=x;tree[k<<1|1].tag+=x;
tree[k].tag=0;
}
inline void upd(int k,int l,int r,int x)
{
gank(k);
if(tree[k].l==l && tree[k].r==r)
{
tree[k].val-=x;tree[k].tag+=x;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
upd(k<<1,l,r,x);
else if(l>mid)
upd(k<<1|1,l,r,x);
else
upd(k<<1,l,mid,x),upd(k<<1|1,mid+1,r,x);
}
inline int getnum(int k,int l)
{
gank(k);
if(tree[k].l==tree[k].r)
return tree[k].val;
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid)
return getnum(k<<1,l);
else
return getnum(k<<1|1,l);
}
inline void mainwork()
{
ansmi=0;
for(int i=n+1;i>=1;i--)
if(b[i]<0)
s[++top]=i;
for(int i=1;i<=n;i++)
if(b[i]>0)
{
while(b[i]>0)
{
if(-b[s[top]]>b[i])
{
ansmi=(ansmi+sqr(s[top]-i)*b[i]%mod)%mod;
b[s[top]]+=b[i];b[i]=0;
break;
}
else
{
ansmi=(ansmi+sqr(s[top]-i)*(-b[s[top]])%mod)%mod;
b[i]+=b[s[top]];b[s[top]]=0;
top--;
}
}
}
top=0;a[0]=-1;s[0]=0;
for(int i=1;i<=n;i++)
{
while(a[i]<=a[s[top]])
top--;
l[i]=s[top]+1;
s[++top]=i;
}
top=0;a[n+1]=-1;s[0]=n+1;
for(int i=n;i>=1;i--)
{
while(a[i]<=a[s[top]])
top--;
r[i]=s[top]-1;
s[++top]=i;
}
build(1,1,n);int x,id;
for(int i=1;i<=n;i++)
{
id=c[i].id;x=getnum(1,id);
ansmx=(ansmx+x*sqr(r[id]-l[id]+1)%mod)%mod;
upd(1,l[id],r[id],x);
}
}
inline void print()
{
printf("%lld %lld",ansmi,ansmx);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}