【启发式合并】Codeforces1037F Maximum Reduction

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82354331

分析:

再次出现F题比E题简单。。。。

这题其实非常的水,那个代码的意义就是:在a序列中,找到所有大小为 k , 2 k 1 , 3 k 1 , 的区间,再将每个区间内的最大值加起来。

然后很容易想到算贡献,对于一个数 a i ,找到它左边第一个不小于它的位置 l i ,以及它右边第一个大于它的位置 r i ,在这两个位置之间,且包含了i的区间,一定是以 a i 为它的值。

找这两个位置是单调栈的基本操作,这里就不赘述了。

然后就可以启发式合并,对每个位置i,分为左右两段: [ l i , i ] , [ i , r i ]
枚举这两段中较小的一段中每个位置 j ,然后算一端为 j ,一端在另一段中的区间有多少,再乘上 a i 作为贡献加进去。然后就可以过了
 

额,感觉这样有点不友好,我还是写写这玩意怎么就是启发式合并了:
首先,把大小关系定义为:如果 a i a j ,满足 a i > a j ( a i = a j i < j ) ,即相等的靠前的更大。

这样一来所有点都不可能相等了。

找到全局最大的一个点,视为根,它一定覆盖了整个序列。剩下的点覆盖的区间一定不会越过这个根。然后再在左侧找一个最大点,右侧找一个最大点,将它们设为根的左右儿子,这样依次递归下去,最后就能建成一颗二叉树。

用启发式合并的思维来看,每次将当前子树的所有元素,贡献到它的父亲那里去,然后和它的兄弟的点数比大小,较小的一个可以支持线性操作。这实质上就是上面的操作。所以这就是启发式合并。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 1000010
#define MOD 1000000007
using namespace std;
typedef long long ll;
int n,k;
ll ans;
ll a[MAXN];
int l[MAXN],r[MAXN];
ll st[MAXN];
int top;
int main(){
    SF("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        SF("%I64d",&a[i]);
    for(int i=1;i<=n;i++){
        while(top>0&&a[st[top]]<a[i])
            top--;
        l[i]=st[top]+1;
        st[++top]=i;
    }
    top=0;
    st[top]=n+1;
    for(int i=n;i>0;i--){
        while(top>0&&a[st[top]]<=a[i])
            top--;
        r[i]=st[top]-1;
        st[++top]=i;
    }
    for(int i=1;i<=n;i++){
        if(i-l[i]<r[i]-i){
            for(int j=l[i];j<=i;j++){
                int minl=i-j;
                int maxl=r[i]-j+1;
                minl=max(minl,k-1);
                if(minl<maxl){
                    ans+=1ll*(max(0,(maxl-1))/(k-1)-max(0,(minl-1))/(k-1))*a[i];
                    ans%=MOD;
                }
            }

        }
        else{
            for(int j=i;j<=r[i];j++){
                int minl=j-i;
                int maxl=j-l[i]+1;
                minl=max(minl,k-1);
                if(minl<maxl){
                    ans+=1ll*(max(0,(maxl-1))/(k-1)-max(0,(minl-1))/(k-1))*a[i];
                    ans%=MOD;
                }
            }
        }
    }
    PF("%I64d",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/82354331
今日推荐