数学+栈/列+思维——namomo round c

最近做的一道很好的题目,感觉很需要直觉才能想到

/*
转化:将a[]转化成差分数组
那么原来的操作[l,r]就变成了a[l]-1,a[r+1]+1
最后的目标是将这个数组的所有元素变成0
为了使操作次数最小,只有两种操作:在正数上的-1操作,在负数上的+1操作,    
                                  并且差分数组每个前缀和必须保持为非负 
(这个结论在差分数组上很容易得出,但是在原数组上就比较难看出来。。)
2 0 2 0 2 _ 最后一个用来占位,代表0 
2 -2 2 -2 2 -2
那么我们就可以推出,代价必定为 sum{(ri-li)^2} = sum{ri^2} + sum{li^2} - sum{2*ri*li}
要求最大代价,那么sum{2*ri*li}要最小,所以用栈维护正数 
要求最小代价,那么sum{2*ri*li}要最大,所以用队列维护正数 
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define mod 1000000007 
#define N 500005
#define fr front()
#define tp top()

ll n,a[N],sum,b[N],base;

void solvemin(){//sum{2*ri*li}最大 
    for(int i=0;i<=n+1;i++)b[i]=a[i];
    queue<ll>q;
    for(int i=1;i<=n+1;i++)    {
        if(b[i]>0)q.push(i);
        else {
            while(abs(b[i])){
                if(abs(b[i])<b[q.fr]){
                    sum=(sum+2ll*q.fr*i%mod*abs(b[i])%mod)%mod;
                    b[q.fr]-=abs(b[i]);b[i]=0;
                    break;
                }
                sum=(sum+2ll*q.fr*i%mod*b[q.fr]%mod)%mod;
                b[i]+=b[q.fr];b[q.fr]=0;
                q.pop();
            }
        }
    }
}
void solvemax(){//sum{2*ri*li}最小 
    for(int i=0;i<=n+1;i++)b[i]=a[i];
    stack<ll>s;
    for(int i=1;i<=n+1;i++){
        if(b[i]>0)s.push(i);
        else {
            while(abs(b[i])){
                if(abs(b[i])<b[s.tp]){
                    sum=(sum+2*s.tp*i%mod*abs(b[i])%mod)%mod;
                    b[s.tp]-=abs(b[i]);b[i]=0;
                    break; 
                }
                sum=(sum+2*s.tp*i%mod*b[s.tp]%mod)%mod;
                b[i]+=b[s.tp];b[s.tp]=0;
                s.pop();
            }
        }
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=n+1;i>=1;i--){
        a[i]=a[i]-a[i-1];
        base=(base+abs(a[i])*i%mod*i%mod)%mod;
    }
    solvemin();cout<<(base-sum+mod)%mod<<' ';sum=0;
    solvemax();cout<<(base-sum+mod)%mod<<'\n';sum=0;
} 

 

posted on 2020-07-09 12:02  zsben  阅读(273)  评论(0编辑  收藏  举报

导航