Codeforces 878 E. Numbers on the blackboard

解题思路

有一种最优策略是每次选择最后面一个大于等于 \(0\) 的元素进行合并,这样做完以后相当于给这个元素乘 \(2\) ,并且不使前面一个元素的值增加了。但是按照这样的策略做不太好维护,考虑做完以后有许多块,除了第一个块以外每一个块都是负的,然后将这些块与第一个块合并。那么用并查集维护一下每个块,每一个元素被乘 \(2\) 的次数就是这个块里面位置比它小的元素个数。定义一个块的和为每个元素乘上其对应系数的和,对于一组询问,答案就是第一块的和加上 \(2\times\) 其它块的和。

考虑怎么解决多组询问,将询问离线下来,对于每一个右端点 \(r_i\) ,如果询问的 \(l_i=1\) ,那么答案就是第一块的和加上 \(2\times\) 其它块的和。否则找到 \(l_i\) 所在的块,这个块以 \(l_i\) 开头的后缀是对于这一询问的"第一个块",因为这个后缀任意时刻是非负的,所以这个后缀的块和就是从右到左直接合并的答案。那么只要维护一下块的前缀和以及一段区间进行从右到左直接合并的答案就好了。

感觉写的非常意识流,多手玩手玩就好了。

code

/*program by mangoyang*/
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast", "inline")
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 1000005, mod = 1e9 + 7;
vector<pair<int, int> > Q[N];
int sz[N], sum[N], s[N], s2[N], ss[N], pw[N], fa[N], a[N], ans[N], n, q;
inline void up(int &x, int y){
x = x + y >= mod ? x + y - mod : x + y;
}
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline int ask(int x){
return x == fa[x] ? x : fa[x] = ask(fa[x]);
}
inline void unite(int x, int y){
int p = ask(x), q = ask(y);
if((sz[p] >= 30 && s[q]) || s[p] + (1ll * s[q] << sz[p]) >= mod) s[p] = mod;
else s[p] = s[p] + (1ll * s[q] << sz[p]);
up(s2[p], 1ll * s2[q] * pw[sz[p]] % mod);
fa[q] = p, sz[p] += sz[q];
}
inline int find(int x, int lim){
int l = 1, r = lim, res = lim + 1;
while(l <= r){
int mid = (l + r) >> 1;
if(ask(mid) > x) res = mid, r = mid - 1;
else l = mid + 1;
}
return res;
}
inline int gao(int x, int y){
return 1ll * (ss[y] - ss[x-1] + mod) % mod * Pow(Pow(2, x), mod - 2) % mod;
}
signed main(){
read(n), read(q), pw[0] = 1;
for(int i = 1; i <= n; i++){
read(a[i]), fa[i] = i, sz[i] = 1;
s[i] = a[i], s2[i] = (a[i] + mod) % mod;
pw[i] = 2ll * pw[i-1] % mod;
ss[i] = (ss[i-1] + 1ll * pw[i] * s2[i] % mod) % mod;
}
for(int i = 1, x, y; i <= q; i++)
read(x), read(y), Q[y].push_back(make_pair(x, i));
for(int i = 1; i <= n; i++){
while(s[ask(i)] >= 0 && ask(i) > 1) unite(ask(i) - 1, i);
sum[ask(i)] = (sum[ask(ask(i)-1)] + 2ll * s2[ask(i)] % mod) % mod;
for(int j = 0; j < (int) Q[i].size(); j++){
int x = Q[i][j].first, y = find(x, i);
int res = (sum[ask(i)] - sum[ask(y-1)] + mod) % mod;
ans[Q[i][j].second] = (res + gao(x, y - 1)) % mod;
}
}
for(int i = 1; i <= q; i++) printf("%d\n", ans[i]);
return 0;
}

Codeforces 878 E. Numbers on the blackboard的更多相关文章

  1. CodeForces 55D "Beautiful numbers"(数位DP+离散化处理)

    传送门 参考资料: [1]:CodeForces 55D Beautiful numbers(数位dp&&离散化) 我的理解: 起初,我先定义一个三维数组 dp[ i ][ j ][ ...

  2. 【CF878E】Numbers on the blackboard 并查集

    [CF878E]Numbers on the blackboard 题意:给你一个长度为n个数列,你每次可以进行如下操作: 选取两个相邻的数x,y(x在y左面),然后将这两个数去掉,用x+2y替换它. ...

  3. Codeforces 55D. Beautiful numbers(数位DP,离散化)

    Codeforces 55D. Beautiful numbers 题意 求[L,R]区间内有多少个数满足:该数能被其每一位数字都整除(如12,24,15等). 思路 一开始以为是数位DP的水题,觉得 ...

  4. CF 878E Numbers on the blackboard 并查集 离线 贪心

    LINK:Numbers on the blackboard 看完题觉得很难. 想了一会发现有点水 又想了一下发现有点困难. 最终想到了 但是实现的时候 也很难. 先观察题目中的这个形式 使得前后两个 ...

  5. CodeForces 151B Phone Numbers

     Phone Numbers Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Sub ...

  6. codeforces 55D - Beautiful numbers(数位DP+离散化)

    D. Beautiful numbers time limit per test 4 seconds memory limit per test 256 megabytes input standar ...

  7. Codeforces 165E Compatible Numbers(二进制+逆序枚举)

    E. Compatible Numbers time limit per test 4 seconds memory limit per test 256 megabytes input standa ...

  8. codeforces Gym 100338E Numbers (贪心,实现)

    题目:http://codeforces.com/gym/100338/attachments 贪心,每次枚举10的i次幂,除k后取余数r在用k-r补在10的幂上作为候选答案. #include< ...

  9. CodeForces 165E Compatible Numbers(位运算 + 好题)

    wo integers x and y are compatible, if the result of their bitwise "AND" equals zero, that ...

随机推荐

  1. Qt TCP通信

    工程文件 QT += network 服务端 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QTcpS ...

  2. Java集合目录

    java集合学习(1):集合框架 java集合学习(2):Map和HashMap Java集合学习(4):HashTable Java集合学习(5):LinkedHashMap Java集合学习(6) ...

  3. rsync免密码远程复制文件

    目标: 从云服务器(112.77.69.212)把mongodb中的文件同步到本地. 步骤一:在云服务器上创建用户 $ adduser monbak $ passwd monbak 步骤二:设置免密登 ...

  4. Jmeter 使用自定义变量

    有些情况下比如发起测试时URL的主机名和端口需要在采样器中出现多次,这样就有个问题,当测试的主机更改时, 我们需要修改主机名称,这时就需要修改多个地方,如果多的情况会有遗漏.如果我们在配置脚本的时候, ...

  5. PAT 乙级 1042.字符统计 C++/Java

    题目来源 请编写程序,找出一段给定文字中出现最频繁的那个英文字母. 输入格式: 输入在一行中给出一个长度不超过 1000 的字符串.字符串由 ASCII 码表中任意可见字符及空格组成,至少包含 1 个 ...

  6. CentOS7 开放端口 通过 firewall-cmd 工具来操作防火墙

    CentOS7 提供了 firewall-cmd 工具来操作防火墙. firewall-cmd --permanent:表示设置为持久,配置被写入配置文件,跨重启,不会立即生效,重新加载配置后生效.不 ...

  7. 知识点5 C++保存txt文件

    简单示例 #include <windows.h> #include <fstream> #include <iostream> #include <stri ...

  8. Codeforces Round #135 (Div. 2) D - Choosing Capital for Treeland(两种树形DP)

  9. LOJ2778 [BOI2018]基因工程 随机化

    题面 不想写了...留坑吧... 基本思想可参照随机化解决判同问题的总结 代码: #include<bits/stdc++.h> using namespace std; #define ...

  10. 第02组Beta冲刺(4/4)

    队名:十一个憨批 组长博客 作业博客 组长黄智 过去两天完成的任务:了解整个游戏的流程 GitHub签入记录 接下来的计划:继续完成游戏 还剩下哪些任务:完成游戏 燃尽图 遇到的困难:没有美术比较好的 ...