[NOI2010]超级钢琴(倍增,贪心,堆)

给你一囗甜甜゛ 提交于 2020-02-08 13:09:26

[NOI2010]超级钢琴(luogu)

Description

题目描述

小 Z 是一个小有名气的钢琴家,最近 C 博士送给了小 Z 一架超级钢琴,小 Z 希望能够用这架钢琴创作出世界上最美妙的音乐。

这架超级钢琴可以弹奏出 nn 个音符,编号为 11 至 nn。第 ii 个音符的美妙度为 A_iAi,其中 A_iAi 可正可负。

一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于 LL 且不多于 RR。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。

小 Z 决定创作一首由 kk 个超级和弦组成的乐曲,为了使得乐曲更加动听,小 Z 要求该乐曲由 kk 个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小 Z 想知道他能够创作出来的乐曲美妙度最大值是多少。

输入格式

输入第一行包含四个正整数 n, k, L, Rn,k,L,R。其中 nn 为音符的个数,kk 为乐曲所包含的超级和弦个数,LL 和 RR 分别是超级和弦所包含音符个数的下限和上限。

接下来 nn 行,每行包含一个整数 A_iAi,表示按编号从小到大每个音符的美妙度。

输出格式

输出只有一个整数,表示乐曲美妙度的最大值。

Solution

先用RMQ预处理出d[i][k]数组:表示点 i 到点 i+(1<<k)-1中前缀和最大的点

然后对于1~n中的每个能作为超级和旋起点的音符构造一个对应的结构体(o,l,r,t)放入大根堆中

(o:起点            l:最小终点           r:最大终点              t:>=l且<=r的使整个超级和旋美妙度最大的终点)

然后使用贪心每次拉出堆顶计入答案,考虑到o为起点时l~t-1和t+1~r中可能还有终点对答案有贡献,特判后一分为二再加入堆中

Code

 

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int N=5e5+10;
long long ans,a[N];
int d[N][20],n,k,l,r;
void pre()
{
    for(int i=1;i<=n;i++) d[i][0]=i;
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            int x=d[i][j-1],y=d[i+(1<<(j-1))][j-1];
            d[i][j]=a[x]>a[y]?x:y;
        }
}
int get(int l,int r)
{
    int k=log2(r-l+1);
    int x=d[l][k],y=d[r-(1<<k)+1][k];
    return a[x]>a[y]?x:y;
}
struct node
{
    int o,l,r,t;
    bool operator <(const node &x)const
    {
        return a[t]-a[o-1]<a[x.t]-a[x.o-1];
    }
};
priority_queue <node> q;
int main()
{
    scanf("%d%d%d%d",&n,&k,&l,&r);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]),a[i]+=a[i-1];
    pre();
    for(int i=1;i+l-1<=n;i++)
        q.push((node){i,i+l-1,min(i+r-1,n),get(i+l-1,min(i+r-1,n))});
    while(k--)
    {
        node tp=q.top();
        q.pop();
        ans+=a[tp.t]-a[tp.o-1];
        if(tp.t!=tp.l) q.push((node){tp.o,tp.l,tp.t-1,get(tp.l,tp.t-1)});
        if(tp.t!=tp.r) q.push((node){tp.o,tp.t+1,tp.r,get(tp.t+1,tp.r)});
    }
    printf("%lld\n",ans);
    return 0;
}

 

 

 

题目描述

小 Z 是一个小有名气的钢琴家,最近 C 博士送给了小 Z 一架超级钢琴,小 Z 希望能够用这架钢琴创作出世界上最美妙的音乐。

这架超级钢琴可以弹奏出 nn 个音符,编号为 11 至 nn。第 ii 个音符的美妙度为 A_iAi,其中 A_iAi 可正可负。

一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于 LL 且不多于 RR。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。

小 Z 决定创作一首由 kk 个超级和弦组成的乐曲,为了使得乐曲更加动听,小 Z 要求该乐曲由 kk 个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小 Z 想知道他能够创作出来的乐曲美妙度最大值是多少。

输入格式

输入第一行包含四个正整数 n, k, L, Rn,k,L,R。其中 nn 为音符的个数,kk 为乐曲所包含的超级和弦个数,LL 和 RR 分别是超级和弦所包含音符个数的下限和上限。

接下来 nn 行,每行包含一个整数 A_iAi,表示按编号从小到大每个音符的美妙度。

输出格式

输出只有一个整数,表示乐曲美妙度的最大值。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!