【bzoj4597】【Shoi2016】【随机序列】【线段树】

来源:互联网 发布:网络拓扑结构可分为 编辑:程序博客网 时间:2024/05/22 05:28

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 5
9384 887 2778 6916 7794
2 8336
5 493
3 1422
1 28
4 60

Sample Output

890543652
252923708
942282590
228728040
608998099
题解:
可以发现加减号之间可以互相抵消.
真正加到答案里的只有一些前缀积.
记s[i]为a[1]*a[2]*a[3]...*a[i].那s[i]在答案中出现的次数就是2*3^(n-i-1);
修改一个数只会对后面的数有影响.
预处理逆元然后用线段树维护即可.
代码:
#include<iostream>#include<cstdio>#include<cstring>#define N 100010#define P 1000000007using namespace std;long long t[N<<2],inv[N],a[N],s[N],bin[N],x,p[N<<2];int n,q,pos;void build(int k,int l,int r){  int mid=(l+r)>>1;  if (l==r){    if (l!=n) t[k]=(s[l]*bin[n-l-1]*2)%P;    else t[k]=s[l];    return;   }  build(k<<1,l,mid);  build(k<<1|1,mid+1,r);  t[k]=(t[k<<1]+t[k<<1|1])%P;}void paint(int k,long long v){  t[k]=(t[k]*v)%P;  p[k]=(p[k]*v)%P;}void pushdown(int k,int l,int r){   int mid=(l+r)>>1;   paint(k<<1,p[k]);   paint(k<<1|1,p[k]);   p[k]=1;}void change(int k,int l,int r,int ll,int rr,long long v){  int mid=(l+r)>>1;  if (ll<=l&&r<=rr){paint(k,v);return;}  if (p[k]!=1) pushdown(k,l,r);  if (ll<=mid) change(k<<1,l,mid,ll,rr,v);  if (mid<rr) change(k<<1|1,mid+1,r,ll,rr,v);  t[k]=(t[k<<1]+t[k<<1|1])%P; }int main(){  scanf("%d%d",&n,&q);  for (int i=1;i<=n;i++) scanf("%lld",&a[i]);   bin[0]=1;  for (int i=1;i<=n;i++) bin[i]=(bin[i-1]*3)%P;  inv[1]=1;   for(int i=2;i<=10000;i++)        inv[i]=(P-(long long)P/i*inv[P%i]%P);  s[1]=a[1];  for (int i=2;i<=n;i++) s[i]=(s[i-1]*a[i])%P;  build(1,1,n);  for (int i=1;i<=n*2;i++) p[i]=1;  for (int i=1;i<=q;i++){      scanf("%d%lld",&pos,&x);    change(1,1,n,pos,n,x*inv[a[pos]]%P);    a[pos]=x;printf("%lld\n",t[1]);  }}


0 0
原创粉丝点击