6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]
题目
题目大意
给你一个数列,每次可以选择任意两个相邻的数\(x\)和\(y\),将其删去,并在原来位置插入\(x+2y\)。
每次询问一个区间,对这个区间进行上述操作。求最后剩下的数最大是多少。
答案需要取模。
思考历程
看到这题,第一个想法是:这题既要搞个最大值,又要取模,所以肯定是贪心。
然而不会……
\(O(n^3)\)的暴力是可以打的,直接区间\(DP\)。然而我没有打。
其实最大的瓶颈是,我需要比大小,然而数太大,会炸掉……
这题题面本身就对暴力不友好……
正解
其实我比赛的时候就发现了一个有趣的性质:
我们把操作看成整个区间分成两个区间,后面的那个区间的系数乘二,然后两边继续递归下去处理。
容易发现,假设\(2……{k_i}\)为第\(i\)项的系数,则\(1\leq k_i \leq k_{i-1}+1\),\(k_1=0\)
可以把答案序列看成几个\(k_i\)的等差数列,每个等差数列的开头都是\(1\)到前一个的结尾(第一个等差数列除外)。
然而有个更加神奇的结论:\(k_i\)要么是\(1\),要么就是\(k_{i-1}+1\)
简单地证明一下:
对于一个等差数列,记一下它的和。如果和大于等于\(0\),则将它接到前面一个等差数列后面会更优;如果小于\(0\),则将开头的\(k\)设为\(1\)最优。
先不要考虑所有的询问。假设询问从\(1\)开始,增量法构造这些等差数列。
首先新增一个节点,\(k_i\)为\(1\),然后试着跟前面合并。
如果大于等于\(0\),就接到前面去。接了之后试着继续跟前面合并。
否则就不接到前面去。
显然这样是没有问题的。
接下来考虑如何处理区间的询问。先离线一下,按照区间右端点排序,询问挂在右端点上。
在统计答案的时候,找到左端点所在等差数列。找的时候可以二分或者并查集。
左端点所在等差数列的后面那些等差数列的和直接加起来。可以用前缀和实现。
左端点可能会将等差数列分成两部分,直接计算后面的那一块就好了。计算的时候可以一开始就预处理\(sum_i=\sum_{j=1}^{i}2^ja_j\),后面的\(sum\)减去\(sum_{l-1}\),再除以\(2^l\)。
为什么分割之后等差数列不会变呢?
其实只需要证明后面的不会合并上来,并且这个也不会继续分裂就行了。
后面的和肯定是负数,所以前面的变了它们也不会合并上来。
如果这个分裂了(假设分裂成\(B\)和\(C\),分割处左边的为\(A\)),原来的和为\(A+2^xB+2^{x+y}C\),在分割之后和变成\(B+2^yC\)。如果它分裂了,就变成\(B+C\).。
各自乘上\(2^x\),加上\(A\),就分别变成了\(A+2^xB+2^{x+y}C\)和\(A+2^xB+2^xC\)
由于前者一定是最优的,所以\(2^yC\geq C\),所以\(C>0\)。
所以它分裂了不会更优。
在实现的时候,它很容易爆掉long long
。实际上,虽然正数很大,但是它最小的负数不会太小。因为在最小的时候,一定是某个等差数列中只有一个负数(如果有几个数从后面合并上来,后面的那几个数的和一定非负数,然后和不会更小)。所以最小是\(-2e9\)。
如果有个数大于\(2e9\),说明它以后永远不会变成负数。记作\(2e9+1\)就行了。
实现的时候要记录一个真的和,用来计算答案(有模);记录一个假的和,用来比大小。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 500010
#define ll long long
#define INF 2000000000
#define mo 1000000007
inline ll my_pow(ll x,int y){
ll res=1;
for (;y;x=x*x%mo,y>>=1)
if (y&1)
res=res*x%mo;
return res;
}
int n,m;
int a[N];
struct Query{
int l,r,num;
} q[N];
inline bool cmpq(Query a,Query b){return a.r<b.r;}
ll ans[N];
ll _2,pow2[N],ipow2[N],bpow2[N],g[N];
int st[N],top;
ll sum[N],rs[N],pre[N];
int main(){
freopen("border.in","r",stdin);
freopen("border.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
_2=my_pow(2,mo-2);
pow2[0]=bpow2[0]=ipow2[0]=1;
for (int i=1;i<=n;++i){
pow2[i]=pow2[i-1]*2%mo;
bpow2[i]=bpow2[i-1]*2;
bpow2[i]=(bpow2[i]>INF?INF+1:bpow2[i]);
ipow2[i]=ipow2[i-1]*_2%mo;
g[i]=(g[i-1]+pow2[i]*a[i])%mo;
}
for (int i=1;i<=m;++i)
scanf("%d%d",&q[i].l,&q[i].r),q[i].num=i;
sort(q+1,q+m+1,cmpq);
st[top=1]=1,pre[1]=sum[1]=rs[1]=a[1];
int j=1;
for (;q[j].r<=1;++j)
ans[q[j].num]=(a[1]+mo)%mo;
for (int i=2;i<=n;++i){
st[++top]=i;
sum[top]=2*a[i];
rs[top]=2ll*(a[i]+mo)%mo;
while (top>1 && sum[top]>=0){
rs[top-1]=(rs[top-1]+rs[top]*pow2[st[top]-st[top-1]-(top==2)])%mo;
sum[top-1]=sum[top-1]+sum[top]*bpow2[st[top]-st[top-1]-(top==2)];
sum[top-1]=(sum[top-1]>INF?INF+1:sum[top-1]);
top--;
}
pre[top]=(pre[top-1]+rs[top])%mo;
st[top+1]=i+1;
for (;j<=m && q[j].r<=i;++j){
int l=2,r=top,x=1;
while (l<=r){
int mid=l+r>>1;
if (st[mid]<=q[j].l)
l=(x=mid)+1;
else
r=mid-1;
}
ans[q[j].num]=((pre[top]-pre[x]+mo)+(g[st[x+1]-1]-g[q[j].l-1])*ipow2[q[j].l]%mo+mo)%mo;
}
}
for (int i=1;i<=m;++i)
printf("%lld\n",ans[i]);
return 0;
}
总结
感觉自己太菜了……
面对贪心的题,一定要敢于下结论……
6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]的更多相关文章
- 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]
题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...
- 【NOIP2019模拟2019.10.07】果实摘取 (约瑟夫环、Mobius反演、类欧、Stern-Brocot Tree)
Description: 小 D 的家门口有一片果树林,果树上果实成熟了,小 D 想要摘下它们. 为了便于描述问题,我们假设小 D 的家在二维平面上的 (0, 0) 点,所有坐标范围的绝对值不超过 N ...
- 6383. 【NOIP2019模拟2019.10.07】果实摘取
题目 题目大意 给你一个由整点组成的矩形,坐标绝对值范围小于等于\(n\),你在\((0,0)\),一开始面向\((1,0)\),每次转到后面第\(k\)个你能看到的点,然后将这条线上的点全部标记删除 ...
- 6392. 【NOIP2019模拟2019.10.26】僵尸
题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...
- 6389. 【NOIP2019模拟2019.10.26】小w学图论
题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...
- 6380. 【NOIP2019模拟2019.10.06】小w与最长路(path)
题目 题目大意 给你一棵树,对于每一条边,求删去这条边之后,再用一条边(自己定)连接两个连通块,形成的树的直径最小是多少. 正解 首先,将这棵树的直径给找出来.显然,如果删去的边不在直径上,那么答案就 ...
- 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋
题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...
- 【NOIP2019模拟2019.9.4】B(期望的线性性)
题目描述: \(1<=n,ai<=5*10^5\) 题解: 我是弱智我不会期望线性. 设\(E(a[i])\)表示第i个期望被减的个数. \(E(a[1])=a[1]\) 不难发现\(E( ...
- 6368. 【NOIP2019模拟2019.9.25】质树
题目 题目大意 有个二叉树,满足每个点跟它的所有祖先互质. 给出二叉树的中序遍历的点权,还原一种可能的方案. 思考历程 首先想到的当然是找到一个跟全部互质的点作为根,然后左右两边递归下去处理-- 然而 ...
随机推荐
- 配置node 的路由
配置路由 引入路由中间件 const Router= require('koa-router'); 实例化 const router= new Router(); 配置路由地址 router.use( ...
- ECUST_Algorithm_2019_2
简要题意及解析 1001 \(N\)个数分为\(K+8\)组,每组三个,记为\((a,b,c)\),方便起见要求\(a \leq b \leq c\),每组的代价是\((a-b)^2\),总代价为每组 ...
- Es学习第五课, 分词器介绍和中文分词器配置
上课我们介绍了倒排索引,在里面提到了分词的概念,分词器就是用来分词的. 分词器是ES中专门处理分词的组件,英文为Analyzer,定义为:从一串文本中切分出一个一个的词条,并对每个词条进行标准化.它由 ...
- java的BigDecimal比较大小
java的BigDecimal比较大小 //前提为a.b均不能为null if(a.compareTo(b) == -1){ System.out.println("a小于b"); ...
- Win10桌面图标显示不正常变成了白色
开机不知道什么原因,windows 10 桌面图标全部变成了白色,软件是可以点击正常打开使用,但是看着特别不爽.今天就告诉大家一种办法,解决这种问题. 解决步骤 1.在桌面右键新建 "文本文 ...
- JVM&GC
先回顾啥是JVM: 引用: 强引用(Strong Reference)•默认的赋值语句可以生成一个强引用•GC时不会被释放 软引用(Soft Reference)•仅被java.lang.ref.So ...
- zabbix监控winserver网卡流量
当前基于windows2008系统安装配置zabbix客户端,服务端为linux系统 1.设置防火墙规则 开启防火墙入站(tcp和udp)10050端口 2.在zabbix官网上下载windows包 ...
- 探索Redis设计与实现12:浅析Redis主从复制
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- python+appium学习总结
经过了这个月的学习,今天终于完成了公司APP系统的自动化的脚本的编写. 通过单元测试框架UNITTEST,进行脚本的连跑,本来还想把测试数据统一写到EXCEL表格内,实现脚本与数据的分离. 后来发现增 ...
- 用FastDFS一步步搭建图片服务器(单机版)
一.FastDFS介绍 FastDFS开源地址:https://github.com/happyfish100 参考:分布式文件系统FastDFS设计原理 参考:FastDFS分布式文件系统 1.简介 ...