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. h5表单亲测

    Document 下载进度: 标签. 牛奶 面包 男 女 one two three 按钮 搜索 请输入搜索内容 加密强度 用户名 Email 密码 年龄 身高 生日 这一系列是很酷的一个类型,完全解 ...

  2. (原)在anaconda3+ubuntu16.04中编译Pose flow中的deepmatching动态库

    转载请注明出处: https://www.cnblogs.com/darkknightzh/p/11285239.html 参考网址: https://github.com/YuliangXiu/Po ...

  3. NetScaler的常用配置

    CITRIX NETSCALER常用功能有:LB,CS,GSLB,SSL LB实现的功能是服务器负载均衡,CS实现基于七层(域名,IP等)的负载均衡,GSLB实现的功能是全局负载均衡,SSL实现的功能 ...

  4. CentOS 7 使用Nexus3搭建maven私服

    安装jdk(略) 安装maven wget http://mirrors.hust.edu.cn/apache/maven/maven-3/3.5.4/binaries/apache-maven-3. ...

  5. Eclipse调用Tomcat出错

    错误提示:The server cannot be started because one or more of the ports are invalid. Open the server edit ...

  6. 遇到libgflags.a(gflags.cc.o): relocation R_X86_64_32 against `.rodata.str1.1' ca时

    glfag编译成动态库gflags 正确的安装方法是这样的: Need cmake >2.8.4 (current is 2.8.3) mkdir build cd build cmake -D ...

  7. getElementsByName兼容ie 但并不是兼容ie下的所有标签

    document.getElementsByName('someName') 返回一个节点列表(数组) document.getElementById('id') 返回一个节点或者null 注意在IE ...

  8. selenium send_keys慢,卡,怎么办?这里有你想要的解决方案

    相信各位看官在用selenium时,会发现发送长字符时,一个字符一个字符在输入,特别在使用chrome时,更加明显. 如果你的网页是要大量编辑的怎么处理呢? 一.send_keys机制 既然问题出来了 ...

  9. PHP 多个字段自增或者自减

    //自增$res=Db::name('accessories') ->where('id',$req['id']) ->inc('number',$req['number']) -> ...

  10. 【java】String与Date转换

    String转Date            String date="";            SimpleDateFormat format=new SimpleDateFo ...