4597: [Shoi2016]随机序列
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 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,表示要将 A
ti 修改为 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
9384 887 2778 6916 7794
2 8336
5 493
3 1422
1 28
4 60
Sample Output
890543652
252923708
942282590
228728040
608998099
252923708
942282590
228728040
608998099
HINT
Source
题目描述得很难很难。。不过真正需要统计的东西其实很少
对于任意一种表达式,把乘号左右两边并起来,这样整个表达式被分为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;
}