bzoj 4597 随机序列

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 取模。
 
题解
首先想到+、-号会导致后面的所有结果相互抵消。所以对答案有贡献的是前面一直是连乘的部分。即第一个非乘号的前面部分
所以我们只需要维护前缀积,修改的时候线段树区间修改,先预处理逆元就可以做了
我认为这道题最关键的地方就是+、-号相互抵消,一下子简化了问题。一开始想是否有规律,真实太蠢了
 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define maxn 100020
 7 
 8 typedef long long ll;
 9 const ll mod = 1e9 + 7;
10 struct node{
11     int ls,rs;
12     ll sum,mul;
13 }sgt[maxn * 4];
14 ll inv[maxn],fac[maxn],sum[maxn],pow[maxn];
15 int n,a[maxn],q,rt,tot;
16 
17 inline ll power(ll x,int y){
18     ll res = 1;
19     while ( y ){
20         if ( y & 1 ) res = res * x % mod;
21         x = x * x % mod;
22         y >>= 1;
23     }
24     return res % mod;
25 }
26 void init(){
27     for (int i = 1 ; i <= 10000 ; i++) inv[i] = power(i,mod - 2);
28     pow[0] = 1;
29     for (int i = 1 ; i <= 100000 ; i++) pow[i] = pow[i - 1] * 3ll % mod;
30 }
31 inline void update(int x){
32     sgt[x].sum = sgt[sgt[x].ls].sum + sgt[sgt[x].rs].sum;
33     if ( sgt[x].sum >= mod ) sgt[x].sum -= mod;
34 }
35 void build(int &x,int l,int r){
36     x = ++tot;
37     sgt[x].mul = 1;
38     if ( l == r ){
39         if ( l == n ) sgt[x].sum = sum[l];
40         else sgt[x].sum = sum[l] * pow[n - l - 1] * 2ll % mod;
41         return;
42     }
43     int mid = (l + r) >> 1;
44     build(sgt[x].ls,l,mid);
45     build(sgt[x].rs,mid + 1,r);
46     update(x);
47 }
48 inline void mul(int x,ll d){
49     sgt[x].sum = sgt[x].sum * (ll)d % mod;
50     sgt[x].mul = sgt[x].mul * (ll)d % mod; 
51 }
52 inline void pushdown(int x){
53     if ( sgt[x].mul != 1 ){
54         mul(sgt[x].ls,sgt[x].mul);
55         mul(sgt[x].rs,sgt[x].mul);
56         sgt[x].mul = 1;
57     }
58 }
59 void modify(int x,int l,int r,int ls,int rs,ll d){
60     if ( ls <= l && rs >= r ){
61         mul(x,d);
62         return;
63     }
64     pushdown(x);
65     int mid = (l + r) >> 1;
66     if ( ls <= mid ) modify(sgt[x].ls,l,mid,ls,rs,d);
67     if ( rs > mid ) modify(sgt[x].rs,mid + 1,r,ls,rs,d);
68     update(x);
69 }
70 int main(){
71     //freopen("input.txt","r",stdin);
72     scanf("%d %d",&n,&q);
73     init();
74     for (int i = 1 ; i <= n ; i++){
75         scanf("%d",&a[i]);
76     }
77     sum[0] = 1;
78     for (int i = 1 ; i <= n ; i++) sum[i] = a[i] * sum[i - 1] % mod;
79     build(rt,1,n);
80     while ( q-- ){
81         int id,v;
82         scanf("%d %d",&id,&v);
83         modify(rt,1,n,id,n,inv[a[id]]);
84         modify(rt,1,n,id,n,v);
85         a[id] = v;
86         printf("%lld
",sgt[rt].sum);
87     }
88     return 0;
89 }
原文地址:https://www.cnblogs.com/zqq123/p/5505857.html