zoukankan      html  css  js  c++  java
  • bzoj2006 [NOI2010]超级钢琴

    Description

    小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少。

    Input

    第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所包含音符个数的下限和上限。 接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。

    Output

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

    Sample Input

    4 3 2 3

    3

    2

    -6

    8

    Sample Output

    11

    【样例说明】
    共有5种不同的超级和弦:

    音符1 ~ 2,美妙度为3 + 2 = 5
    音符2 ~ 3,美妙度为2 + (-6) = -4
    音符3 ~ 4,美妙度为(-6) + 8 = 2
    音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
    音符2 ~ 4,美妙度为2 + (-6) + 8 = 4
    最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5 + 2 + 4 = 11。

    真是蛋疼死了……一开始想法有点不对wa来wa去的停不下来,最后又因为log预处理的时候数组开小re了

    题意是给定一个序列,要求序列所有子串和中前k大的和,并且限制子串的长度在L到R之间

    这题没做过类似的真的有点难

    首先令三元组(i,l,r)表示所有左端点在i,右端点在区间[l,r]中的所有子串中sum(i,t)最大的那个t

    把这些三元组扔进堆里,然后每次提一个sum(i,t)最大的子串出来,再加入(i,l,t-1)和(i,t+1,r)

    对于查找(i,l,r)中的t的操作,就是要求sum(i,t)最大的t,l<=t<=r

    显然这个等价于求sum(1,t)前缀和最大

    于是又变成在区间[l,r]中查询前缀和的最大值,显然RMQ搞定。这个预处理nlogn,查询O(1)

    因为只要做k次,每次最多删去1个加入2个相当于加入1个,所以复杂度nlogn+klog(n+k)

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #define N 1500010
    #define LL long long
    #define mkp(a,b,c,d) (dat){a,b,c,d}
    using namespace std;
    inline LL read()
    {
    	LL x=0,f=1;char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-')f*=-1;ch=getchar();}
    	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    struct dat{int l,r,i,t;};
    priority_queue <dat,vector<dat> > q;
    int n,k,L,R;
    int a[N],s[N];
    LL ans;
    int lg[N],bin[21];
    int mx[N][21];
    inline bool operator <(const dat &a,const dat &b)
    {return s[a.t]-s[a.i-1]<s[b.t]-s[b.i-1];}
    inline void pre()
    {
    	lg[0]=-1;for (int i=1;i<=n;i++)lg[i]=lg[i>>1]+1;
    	bin[0]=1;for (int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
    	for (int i=1;i<=n;i++)mx[i][0]=i;
    	for (int i=1;i<=lg[n];i++)
    	  for (int j=1;j<=n-bin[i]+1;j++)
    	  {
    	  	int t1=mx[j][i-1],t2=mx[j+bin[i-1]][i-1];
    	  	if (s[t1]>s[t2])mx[j][i]=t1;else mx[j][i]=t2;
    	  }
    }
    inline int query(int l,int r)
    {	
    	if (l==r)return l;
    	int res=lg[r-l+1];
    	int t1=mx[l][res],t2=mx[r-bin[res]+1][res];
    	if (s[t1]>s[t2])return t1;
    	else return t2;
    }
    int main()
    {
    	n=read();k=read();L=read();R=read();
    	for (int i=1;i<=n;i++)a[i]=read();
    	for (int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
    	pre();
    	for (int i=1;i<=n;i++)
    	{
    		if (i+L-1>n)break;
    		int Lt=i+L-1;
    		int Rt=min(i+R-1,n);
    		int fuck=query(Lt,Rt);
    		q.push(mkp(Lt,Rt,i,fuck));
    	}
    	for (int i=1;i<=k;i++)
    	{
    		dat now=q.top();q.pop();
    		ans+=(LL)s[now.t]-s[now.i-1];
    		if (now.t-1>=now.l)q.push(mkp(now.l,now.t-1,now.i,query(now.l,now.t-1)));
    		if (now.r>=now.t+1)q.push(mkp(now.t+1,now.r,now.i,query(now.t+1,now.r)));
    	}
    	printf("%lld
    ",ans);
    }
    
    ——by zhber,转载请注明来源
  • 相关阅读:
    Python导学基础(三)输入、格式化输出、基本运算符
    题解-FJOI2014 树的重心
    题解-CF1307G Cow and Exercise
    题解-SHOI2005 树的双中心
    笔记-CF643E Bear and Destroying Subtrees
    题解-CF643G Choosing Ads
    扩展Lucas
    线性筛筛积性函数
    整除分块(数论)
    2019暑假集训DAY17(problem2.b)(杜教筛)
  • 原文地址:https://www.cnblogs.com/zhber/p/4160491.html
Copyright © 2011-2022 走看看