4597: [Shoi2016]随机序列

来源:互联网 发布:vue 源码 编辑:程序博客网 时间:2024/06/11 19:57

4597: [Shoi2016]随机序列

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 168  Solved: 115
[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 5
9384 887 2778 6916 7794
2 8336
5 493
3 1422
1 28
4 60

Sample Output

890543652
252923708
942282590
228728040
608998099

HINT

Source

By 佚名上传

[Submit][Status][Discuss]



题目描述得很难很难。。不过真正需要统计的东西其实很少

对于任意一种表达式,把乘号左右两边并起来,这样整个表达式被分为k个部分

除了第一部分,后面每部分对最终答案都没有贡献

因为这样的东西出现多少次+就会有多少个带-的式子和它抵消= =

也就是说,每个表达式对ans的贡献就是从第一个数字开始,到第一个不是*前面的数字的乘积

那么,有

单点修改的话影响后面一串,利用逆元消除之前的影响,区间修改即可

那当然是线段树维护了= =


一开始居然忘记在Modify操作里打pushdown。。。惨

可是,,,这题数据好弱啊。。。。题面里不是说非负数么!!

非负数啊,0哪里有逆元?????

但是bzoj只有三组数据。。三组,而且每一组里的数字全是正的。。

如果位置k的数字为0,那么k及其之后算出的结果都是0

可以不进行修改转而打标记

询问的话只要找到左数第一个非0位,把左边的答案拿出来就好了

用配对堆易于实现

#include<iostream>  #include<cstdio>  #include<algorithm>  #include<cstring>  #include<ext/pb_ds/priority_queue.hpp>  using namespace std;    const int maxn = 1E5 + 10;  const int T = 4;  typedef long long LL;  const LL mo = 1000000007;  typedef __gnu_pbds::priority_queue<int,greater<int>,__gnu_pbds::pairing_heap_tag> Heap;    int n,m,A[maxn],F[maxn],mi[maxn],c[maxn*T],Mark[maxn*T];  bool zeo[maxn];    Heap Q;  Heap::point_iterator id[maxn];    int Mul(const LL &x,const LL &y) {return x*y%mo;}  int Add(const LL &x,const LL &y) {return (x + y)%mo;}    void pushdown(int o,int l,int r)  {      if (Mark[o] == 1) return;      c[o] = Mul(c[o],Mark[o]);      if (l == r) {Mark[o] = 1; return;}      Mark[o<<1] = Mul(Mark[o<<1],Mark[o]);      Mark[o<<1|1] = Mul(Mark[o<<1|1],Mark[o]);      Mark[o] = 1;  }    void Build(int o,int l,int r)  {      if (l == r)      {          c[o] = Mul(F[l],mi[l]);          Mark[o] = 1; return;      }         int mid = (l + r) >> 1; Mark[o] = 1;      Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);      c[o] = Add(c[o<<1],c[o<<1|1]);  }    void Modify(int o,int l,int r,int ml,int mr,int x)  {      if (ml <= l && r <= mr)      {          Mark[o] = Mul(Mark[o],x);          pushdown(o,l,r); return;      }      int mid = (l + r) >> 1; pushdown(o,l,r);      if (ml <= mid) Modify(o<<1,l,mid,ml,mr,x); else pushdown(o<<1,l,mid);      if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,x); else pushdown(o<<1|1,mid+1,r);      c[o] = Add(c[o<<1],c[o<<1|1]);  }    int ksm(int x,int y)  {      int ret = 1;      for (; y; y >>= 1)      {          if (y&1) ret = Mul(ret,x);          x = Mul(x,x);      }      return ret;  }    int Query(int o,int l,int r,int ql,int qr)  {  pushdown(o,l,r);    if (ql <= l && r <= qr) return c[o];      int mid = (l + r) >> 1,ret = 0;      if (ql <= mid) ret = Add(ret,Query(o<<1,l,mid,ql,qr));      if (qr > mid) ret = Add(ret,Query(o<<1|1,mid+1,r,ql,qr));      return ret;  }    int main()  {      #ifdef DMC          freopen("DMC.txt","r",stdin);      #endif            cin >> n >> m; F[0] = mi[n] = 1; mi[n-1] = 2;      id[n+1] = Q.push(n+1);      for (int i = 1; i <= n; i++)       {          scanf("%d",&A[i]);          if (!A[i]) id[i] = Q.push(i),A[i] = 1,zeo[i] = 1;          F[i] = Mul(A[i],F[i-1]);      }      for (int i = n - 2; i > 0; i--) mi[i] = Mul(mi[i+1],3);      Build(1,1,n);      while (m--)      {          int pos,x; scanf("%d%d",&pos,&x);          if (zeo[pos] && x)          {              Q.erase(id[pos]);              Modify(1,1,n,pos,n,Mul(ksm(A[pos],mo-2),x));              A[pos] = x; zeo[pos] = 0;          }          else if (!zeo[pos] && !x) id[pos] = Q.push(pos),zeo[pos] = 1;          else if (!zeo[pos] && x)          {                 Modify(1,1,n,pos,n,Mul(ksm(A[pos],mo-2),x));              A[pos] = x;           }          int k = Q.top();          if (k > 1)              printf("%d\n",Query(1,1,n,1,k-1));          else puts("0");      }      return 0;  }

0 0
原创粉丝点击