zoukankan      html  css  js  c++  java
  • 【CF878E】Numbers on the blackboard(贪心)

    题目链接

    • 给定一个长度为 (n) 的序列 (a_{1sim n})
    • (q) 次询问,每次取出序列中的一个区间 ([l,r]) 内的元素进行操作。
    • 一次操作可以合并相邻两个元素(假设依次为 (x)(y)),得到一个值为 (x+2y) 的新元素。对于每次询问,求出求最终能得到的元素的最大值。
    • (1le n,qle10^5)(|a_i|le10^9),答案向 (10^9+7) 取模

    巧妙的贪心策略

    设第 (i) 个元素对答案的贡献系数为 (2^{k_i})

    除开头元素外,第 (i) 个元素都至少被合并一次,且一次合并之后就会始终跟随着第 (i-1) 个元素,也就是说 (1le k_ile k_{i-1}+1)

    而我们肯定想让正数的系数尽可能大,因此如果一个数是正数,我们肯定贪心地让 (k_i) 取满 (k_{i-1}+1)

    考虑把 (k_i) 连续递增的一段元素称作一个块。

    则正数肯定会被添到上一个块的末尾,负数则会自成一个新块。

    但要,如果正数被添到上一个块末尾后上一个块的权值变成了正数,我们需要继续把这个块看成一个元素向前合并。具体实现可以用一个栈来维护所有的块,要保证除第一个块之外的所有块权值为负。

    注意用于判断正负的权值是不能取模的,而如果无脑维护可能会爆 long long。实际上,当权值非常大时,肯定能一路向前合并完,可以统一设为 INF。

    离线询问

    询问可以离线,按右端点 (r) 排序,这样我们就可以维护好加入 (1sim r) 中所有元素的局面,然后每次 lower_bound 找出第 (l) 个元素所在的块(假设为 (x))。

    (l) 到所在块结尾 (ed) 中第 (i) 个元素贡献系数为 (2^{i-l}),只需用 (sum_{i=l}^{ed}a_i imes 2^i) 除以 (2^l),这可以预处理一个前缀和差分求解。

    而第 (x+1) 个块开始的答案就是这些块的权值和,同样维护前 (i) 个块的权值和每次差分一下即可。

    注意除开头元素外,每个元素至少合并一次,(k_ige 1)

    代码:(O(nlog n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Rg register
    #define RI Rg int
    #define Cn const
    #define CI Cn int&
    #define I inline
    #define W while
    #define N 100000
    #define X 1000000007
    #define I2 500000004
    #define LL long long
    #define INF (LL)1e18
    using namespace std;
    int n,a[N+5],ans[N+5];struct Q {int p,l,r;I bool operator < (Cn Q& o) Cn {return r<o.r;}}q[N+5];
    int pw[N+5],ipw[N+5],S[N+5],V[N+5],St[N+5],F[N+5];LL G[N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int ff,OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0,ff=1;W(!isdigit(oc=tc())) ff=oc^'-'?1:-1;W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));x*=ff;}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    int main()
    {
    	RI Qt,i;for(read(n,Qt),i=1;i<=n;++i) read(a[i]);for(i=1;i<=Qt;++i) read(q[i].l,q[i].r),q[i].p=i;
    	for(pw[0]=ipw[0]=i=1;i<=n;++i) pw[i]=2LL*pw[i-1]%X,ipw[i]=1LL*I2*ipw[i-1]%X,S[i]=(S[i-1]+1LL*pw[i]*(a[i]+X))%X;//预处理
    	RI x,j=1,T=0;for(sort(q+1,q+Qt+1),i=1;i<=n;++i)//将询问离线,枚举右端点
    	{
    		St[++T]=i,F[T]=(a[i]+X)%X,G[T]=a[i];//新开一个块
    		W(T>1&&G[T]>=0) x=St[T]-St[T-1],F[T-1]=(F[T-1]+1LL*F[T]*pw[x])%X,G[T-1]=G[T-1]+1.0*G[T]*pw[x]>=INF?INF:G[T-1]+G[T]*pw[x],--T;//若最后一个块权值非负,向前合并
    		V[T]=(V[T-1]+F[T])%X,St[T+1]=i+1;//V记录前i块元素之和
    		W(j<=Qt&&q[j].r==i) x=upper_bound(St+1,St+T+1,q[j].l)-St,ans[q[j].p]=(1LL*ipw[q[j].l]*(S[St[x]-1]-S[q[j].l-1]+X)+2LL*(V[T]-V[x-1]+X))%X,++j;//找到l所在块求解
    	}
    	for(i=1;i<=Qt;++i) writeln(ans[i]);return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    五分钟带你了解啥是JWT
    软件系统方案设计
    基于工程实践的需求分析和概念原型
    Linux添加环境变量与GCC编译器添加INCLUDE与LIB环境变量
    ssh链接到minikube虚拟机
    error converting YAML to JSON: yaml: line 3: mapping values are not allowed in this context
    CentOS 7 virt-manager “authentication failed”错误及解决方法
    centos安装docker
    kali安装php-gd
    mariadb忘记root密码
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF878E.html
Copyright © 2011-2022 走看看