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. oracle 查询角色具有的权限

    select * from dba_tab_privs where GRANTEE='角色名';

  2. druid + mysql + mybatis 批量更新报错

    首先 批量更新报错 sql injection violation, multi-statement not allow 然后看了博客:https://blog.csdn.net/qq_3634595 ...

  3. Ajax请求设置csrf_token

    方式1 通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送. $.ajax({ url: "/cookie_ajax/", type: ...

  4. JavaScript 关于金额、数字验证的正则表达式

    JavaScript 关于金额.数字验证的正则表达式 function ismoney(money) { var reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^ ...

  5. react小项目

    本章要讲述一个评价栏的制作. 首先先简单写一个ract组件来试试. index.html <!DOCTYPE html> <html> <head> <tit ...

  6. css display:inline

  7. Python并发编程之进程同步

    """ 问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱的问题 """ ''' 进程同步 ''' #多进程抢占输出资源 ...

  8. 五个goland进行go开发的小技巧

    五个goland进行go开发的小技巧 本文译自5 Tips To Speed Up Golang Development With IntelliJ Or Goland 确实很实用. 1. 实现int ...

  9. vmtools的功能

    1.vmtoools是vmware公司的组件 2.vmtools主要安装在Guest OS中 3.在workstation版本中可以是选件安装,但在vsphere中却是必选安装 4.vmtools可以 ...

  10. 【字符串】KMP

    Algorithm Task 给定一个文本串 \(S\) 和一个模式串 \(T\),求 \(T\) 在 \(S\) 中出现的所有位置. Limitations 要求时空复杂度均为线性. Solutio ...