首页 > 其他分享 >【做题记录】CF878E

【做题记录】CF878E

时间:2022-09-20 21:12:37浏览次数:66  
标签:cnt CF878E return val 记录 int ll mod

让正数带的系数尽量大。
如果要使系数最小的话,全部从左往右合并,可以让除了左端点之外全部系数为 \(2\) 。
如果增大系数可以考虑先右再左。
那么实际上就是分成若干组,组内从右往左,组外从左往右,也就是组内系数为 \(1,2,4,8,\cdots\) 。值得注意的是除了第一组外都多一个 \(2\) 的系数。
分组:先将每个数分别开一组,将总和为正的组往左合并,容易发现这得到的分组方式是唯一的。

将询问离线,增量法每次直接尽量往左合并,询问时需要二分出左端点在哪个块,空缺的块贡献用前缀和之类的方法去除。

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const int N=1e5+10, mod=1e9+7, inv2=5e8+4;
int n,T,a[N],cnt,q[N],siz[N],mi[N],imi[N],pre[N];
int sum[N];
ll val[N];
struct que{
	int l,r,id;
}q1[N];
int ans[N];
bool cmp(que a,que b){return a.r<b.r;}
int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
int dec(int a,int b){return a>=b?a-b:a-b+mod;}
int calc(int x,int y){
	if(val[y]==mod)return mod;
	int len=q[y]-q[x];ll ret=val[y];
	fo(i,1,len){
		ret=ret*2;
		if(ret+val[x]>=mod)return mod;
	}
	return ret+val[x];
}
int main(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	scanf("%d%d",&n,&T);
	mi[0]=imi[0]=1;
	fo(i,1,n){
		scanf("%d",&a[i]);
		mi[i]=(ll)mi[i-1]*2%mod;
		imi[i]=(ll)imi[i-1]*inv2%mod;
		int v=(a[i]<0?a[i]+mod:a[i]);
		pre[i]=((ll)v*mi[i-1]%mod + pre[i-1]) % mod;
	}
	fo(i,1,T){
		scanf("%d%d",&q1[i].l,&q1[i].r);
		q1[i].id=i;
	}
	sort(q1+1,q1+T+1,cmp);
	for(int i=1,j=1;i<=n && j<=T;++i){
		q[++cnt]=i;val[cnt]=a[i];siz[cnt]=(a[i]+mod)%mod;
		sum[cnt]=add(sum[cnt-1],siz[cnt]);
		for(;cnt>1 && val[cnt]>0;){
			--cnt;
			val[cnt]=calc(cnt,cnt+1);
			siz[cnt]=((ll)siz[cnt+1]*mi[q[cnt+1]-q[cnt]] % mod + siz[cnt]) % mod;
			sum[cnt]=add(sum[cnt-1],siz[cnt]);
		}
		q[cnt+1]=i+1;
		for(;j<=T && q1[j].r==i;++j){
			int l=1,r=cnt+1,mid;
			while(l<r-1){
				mid=l+r>>1;
				if(q[mid]<=q1[j].l)l=mid;
				else r=mid;
			}
			int ret=dec(sum[cnt],sum[l-1]);
			if(q1[j].l==q[l]){ans[q1[j].id]=add(ret, dec(sum[cnt],sum[l]) );continue;}
			else{
				int L=q1[j].l,R=q[l+1]-1;
				ret=dec(ret , siz[l]);ret=(ret*2)%mod;
				int ret1=(ll)dec(pre[R] , pre[L-1]) * imi[L-1] % mod;
				ret=add(ret , ret1);
				ans[q1[j].id]=ret;
			}
		}
	}
	fo(i,1,T)printf("%d\n",ans[i]);

	return 0;
}

标签:cnt,CF878E,return,val,记录,int,ll,mod
From: https://www.cnblogs.com/Kelvin2005/p/16712541.html

相关文章

  • 数据库课堂学习记录
    建表插入数据      创建连线  错误原因:忘记设置主键了   在MySQL的命令行工具里 输入SHOWVARIABLESLIKE'datadir';命令,返回数据库文......
  • 思维题做题记录
    博弈论-CF1728D先明确一些事情:对于str[l,r],若A先手,最后的结果是确定的。(这里的字符串长度为偶数)现在,我们设\(f_{l,r}\)表示对于字符串[l,r],A先手的博弈......
  • 前端基础知识-css(一)个人学习记录
    待补充flex及其属性https://blog.csdn.net/weixin_44706267/article/details/121291934css3新特性sass和lesshttps://www.cnblogs.com/dasusu/p/10114097.html......
  • 做题记录整理dp3 P1108. 低价购买(2022/9/20)
    P1108.低价购买第一问很明显是一个最长下降子序列第二问就是一个求方案数,有点难想的就是去重感觉这题难度标的有点偏高#include<bits/stdc++.h>#definefor1(i,a,b)......
  • 做题记录整理dp1 P1282. 多米诺骨牌(2022/9/20)
    P1282.多米诺骨牌我们可以把每张骨牌的差值塞进dp的维度了,就变成dpi,j表示前i块骨牌的差值为j的最小旋转次数就可以有递推方程dp[i,j]=max(dp[i-1,j-(a[i]-b[i])],dp[i......
  • 做题记录整理dp1 P1541. [NOIP2010 提高组] 乌龟棋(2022/9/20)
    P1541.[NOIP2010提高组]乌龟棋把每个牌选多少个塞进dp的四个维度里,就可以做到无后效性了#include<bits/stdc++.h>usingnamespacestd;#definefor1(i,a,b)for(ll......
  • D8加密狗的使用过程记录
    1、安装VSCode,并且安装插件   2、打开商家给提供的文件夹【打开的是整个文件夹】如下: 打开后效果如下: 3、编写加密锁里的逻辑打......
  • 做题记录整理线段树2 P4513. 小白逛公园(2022/9/20)
    P4513.小白逛公园我们思考一个如何使用线段树维护这个答案,会发现l.r的答案=max(l,mid的答案,mid+1,r的答案,横跨两个区间的答案)那么我们现在再引入一个区间的最大前缀......
  • 每日记录
    很急,很急,逃了很多课,却没刷几道题,很急,急死了,拖后腿就是我了,急急急急急急!!!2022年9月昨晚Div2看漏条件,演了半天.逃了线代和选修,然后tm的去学线代速......
  • 9.20Leetcode记录
    一、字符串的排列题干:输入一个字符串,打印出该字符串中字符的所有排列。你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。示例:输入:s="abc"输出:["abc","a......