[bzoj4597][Shoi2016]随机序列 线段树
2017-09-29 19:21
369 查看
4597: [Shoi2016]随机序列
Time Limit: 20 Sec Memory Limit: 256 MB[Submit][Status][Discuss]
Description
你的面前有N个数排成一行。分别为A1, A2, … , An。你打算在每相邻的两个 Ai和 Ai+1 间都插入一个加号或者减号或者乘号。那么一共有 3^(n-1) 种可能的表达式。你对所有可能的表达式的值的和非常感兴趣。但这毕竟太
简单了,所以你还打算支持一个修改操作,可以修改某个Ai 的值。你能够编写一个程序对每个修改都输出修改完
之后所有可能表达式的和吗?注意,修改是永久的,也就是说每次修改都是在上一次修改的基础上进行, 而不是
在最初的表达式上进行。
Input
第一行包含 2 个正整数 N 和 Q,为数的个数和询问的个数。接下来一行 n 个非负整数,依次表示a1,a2...an
在接下来 Q 行,其中第 ?? 行两个非负整数Ti 和Vi,表示要将 Ati 修改为 Vi。其中 1 ≤ Ti ≤ N。
保证对于 1 ≤ J ≤ N, 1 ≤ i≤ Q,都有 Aj,Vi ≤ 10^4。
N,Q<=100000,本题仅有三组数据
Output
输出共 Q 行,其中第 i 行表示第 i 个询问之后所有可能表达式的和,对10^9 + 7 取模。Sample Input
5 59384 887 2778 6916 7794
2 8336
5 493
3 1422
1 28
4 60
Sample Output
890543652252923708
942282590
228728040
608998099
HINT
看来我被这道题骗了一个等式
{前}+{后}
{前}-{后}
加起来
等于
2*{前}
于是此题就是维护一个值
fac[i]表示a[1]*a[2]*a[3]...a[i]
sigma 2*fac[i]*3^(n-i-1) + fac
为什么?(还需要解释吗)
fac[i]仅存在于第i位是+或-号,前面均为*,+ - * 有(n-1)- i 位,就是3的那么多次方
所以区间乘法就完了
为甚么我的线段树常数下不来!!!
逆元用欧拉定理预处理(只有10000)
#include <bits/stdc++.h> using namespace std; const int N = 1000000 + 5; const int mod = 1e9 + 7; int inv[10005],n,q,fac ,a ,sum[N<<2],flag[N<<2]; int quik_pow( int x, int p ){ int ret = 1; while( p ){ if( p & 1 ) ret = 1LL * ret * x % mod; x = 1LL * x * x % mod; p >>= 1; } return ret; } void pushdown( int k ){ if( flag[k] != 1 ){ flag[k<<1] = 1LL * flag[k<<1] * flag[k] % mod; flag[k<<1|1] = 1LL * flag[k<<1|1] * flag[k] % mod; sum[k<<1] = 1LL * sum[k<<1] * flag[k] % mod; sum[k<<1|1] = 1LL * sum[k<<1|1] * flag[k] % mod; flag[k] = 1; } } void update( int k ){ sum[k] = ( sum[k<<1] + sum[k<<1|1] ) % mod; } void build( int k, int l, int r ){ flag[k] = 1; if( l == r ){ if( l == n ) sum[k] = fac[l]; else sum[k] = 1LL * fac[l] * ( 2LL * quik_pow( 3, n - l - 1 ) % mod ) % mod; return ; } int mid = l + r >> 1; build( k<<1, l, mid ); build( k<<1|1, mid+1, r ); update( k ); } void change( int k, int l, int r, int L, int R, int x ){ if( l >= L && r <= R ){ sum[k] = 1LL * sum[k] * x % mod; flag[k] = 1LL * flag[k] * x % mod; return ; } pushdown( k ); int mid = l + r >> 1; if( mid >= L ) change( k<<1, l, mid, L, R, x ); if( mid < R ) change( k<<1|1, mid+1, r, L, R, x ); update( k ); } int main(){ fac[0] = 1; for( int i = 1; i <= 10000; i++ ) inv[i] = quik_pow( i, mod-2 ); scanf( "%d%d", &n, &q ); for( int i = 1; i <= n; i++ ) scanf( "%d", &a[i] ), fac[i] = 1LL * fac[i-1] * a[i] % mod; build( 1, 1, n ); while( q-- ){ int x,y; scanf( "%d%d", &x, &y ); int yy= 1LL * y * inv[a[x]] % mod; change( 1, 1, n, x, n, yy ); a[x] = y; printf( "%d\n", sum[1] ); } return 0; }明天我就16岁了,成为一位长者
相关文章推荐
- [BZOJ4597][SHOI2016]随机序列(线段树)
- 【BZOJ4597】[Shoi2016]随机序列 线段树
- 【bzoj4597】[Shoi2016]随机序列 线段树
- 【BZOJ4597】【Shoi2016】随机序列 线段树
- bzoj 4597: [Shoi2016]随机序列 线段树
- 【bzoj4597】【Shoi2016】【随机序列】【线段树】
- BZOJ 4597: [Shoi2016]随机序列
- bzoj 4597: [Shoi2016]随机序列
- 【bzoj4597】 [Shoi2016]随机序列
- bzoj4597 [Shoi2016]随机序列
- 4597: [Shoi2016]随机序列
- bzoj4596 [Shoi2016]黑暗前的幻想乡
- 【BZOJ4519】【Sdoi2016】游戏 线段树
- [bzoj]4596: [Shoi2016]黑暗前的幻想乡
- BZOJ 4408: [Fjoi 2016]神秘数 可持久化线段树
- BZOJ 4571: [Scoi2016]美味(权值线段树查询最大异或和)
- BZOJ[1018][SHOI2008]堵塞的交通traffic 线段树
- BZOJ 4574: [Zjoi2016]线段树/UOJ #196. 【ZJOI2016】线段树 dp
- 数据结构(线段树):BZOJ 1018: [SHOI2008]堵塞的交通traffic
- BZOJ 4653: [Noi2016]区间 线段树