[SHOI2016] 随机序列
4597: [Shoi2016]随机序列
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 327 Solved: 192
[Submit][Status][Discuss]
Description
你的面前有N个数排成一行。分别为A1, A2, … , An。你打算在每相邻的两个 Ai和 Ai+1 间都插入一个加号或者
减号或者乘号。那么一共有 3^(n-1) 种可能的表达式。你对所有可能的表达式的值的和非常感兴趣。但这毕竟太
简单了,所以你还打算支持一个修改操作,可以修改某个Ai 的值。你能够编写一个程序对每个修改都输出修改完
之后所有可能表达式的和吗?注意,修改是永久的,也就是说每次修改都是在上一次修改的基础上进行, 而不是
在最初的表达式上进行。
Input
第一行包含 2 个正整数 N 和 Q,为数的个数和询问的个数。
接下来一行 n 个非负整数,依次表示a1,a2...an
在接下来 Q 行,其中第 i 行两个非负整数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
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
一个非常神奇的事情是,只有第一个由*连成的联通块对答案有贡献,后面的联通块都没有贡献。
虽然说是神奇,但还是比较显而易见的233。就比如我们再填上+和-之前,*已经连出了若干联通块,我们只需要在剩下的空当中填上+或-即可完成一次操作。然而每一种操作都对应着有且只有一个反操作,使得除了*都相同以外,一种操作填+的位置在另一种中都是-,而填-的位置都是+,那么两种操作的和就是第一个由*连成的联通块的元素积*2,剩下的联通块的积都被抵消掉了。
所以答案就是 a[1] * 2 * 3^(n-2) + ..... a[1] * a[2] * a[3] * ... * a[n-1] * 2 + a[1] * a[2] *...* a[n]。
于是我们就可以在线段树 的每个位置维护 a[1] * ...* a[i] * 2 * 3^(n-i-1) [或者a[1] *..... *a[n]] ;
修改的话,就是一个后缀区间乘上一个数,直接做就行了。
但是为什么在洛谷上我的标记永久化线段树 被 下传标记的线段树 艹爆了 2333,而在bzoj 却是相反的情况。。。
这是标记下传的:
/************************************************************** Problem: 4597 User: JYYHH Language: C++ Result: Accepted Time:584 ms Memory:6372 kb ****************************************************************/ #include<bits/stdc++.h> #define ll long long using namespace std; const int ha=1000000007; const int maxn=100005; int a[maxn],f[maxn],hz,pos,qz[maxn]; int c[maxn],n,Q,val,ans,b[maxn],w; int tag[maxn*4],sum[maxn*4],le,ri; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } inline void maintain(int o,int lc,int rc){ sum[o]=add(sum[lc],sum[rc]); } inline void change(int o,int MUL){ tag[o]=tag[o]*(ll)MUL%ha; sum[o]=sum[o]*(ll)MUL%ha; } inline void pushdown(int o,int lc,int rc){ if(tag[o]>1){ change(lc,tag[o]),change(rc,tag[o]); tag[o]=1; } } void build(int o,int l,int r){ tag[o]=1; if(l==r){ sum[o]=(l==n?qz[l]:qz[l]*2ll*(ll)c[n-l-1]%ha); return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; build(lc,l,mid),build(rc,mid+1,r); maintain(o,lc,rc); } void update(int o,int l,int r){ if(l>=le&&r<=ri){ change(o,w); return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; pushdown(o,lc,rc); if(le<=mid) update(lc,l,mid); if(ri>mid) update(rc,mid+1,r); maintain(o,lc,rc); } inline void solve(){ build(1,1,n); while(Q--){ scanf("%d%d",&pos,&val); le=pos,ri=n,w=val*(ll)ksm(a[pos],ha-2)%ha; a[pos]=val; update(1,1,n); printf("%d\n",sum[1]); } } int main(){ scanf("%d%d",&n,&Q),c[0]=qz[0]=1; for(int i=1;i<=n;i++) c[i]=add(c[i-1],add(c[i-1],c[i-1])); for(int i=1;i<=n;i++){ scanf("%d",a+i); qz[i]=qz[i-1]*(ll)a[i]%ha; } solve(); return 0; }
然后标记永久化的
/************************************************************** Problem: 4597 User: JYYHH Language: C++ Result: Accepted Time:460 ms Memory:6372 kb ****************************************************************/ #include<bits/stdc++.h> #define ll long long using namespace std; const int ha=1000000007; const int maxn=100005; int a[maxn],f[maxn],hz,pos,qz[maxn]; int c[maxn],n,Q,val,ans,b[maxn],w; int tag[maxn*4],sum[maxn*4],le,ri; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } inline void maintain(int o,int lc,int rc){ sum[o]=tag[o]*(ll)add(sum[lc],sum[rc])%ha; } inline void change(int o,int MUL){ tag[o]=tag[o]*(ll)MUL%ha; sum[o]=sum[o]*(ll)MUL%ha; } void build(int o,int l,int r){ tag[o]=1; if(l==r){ sum[o]=(l==n?qz[l]:qz[l]*2ll*(ll)c[n-l-1]%ha); return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; build(lc,l,mid),build(rc,mid+1,r); maintain(o,lc,rc); } void update(int o,int l,int r){ if(l>=le&&r<=ri){ change(o,w); return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; if(le<=mid) update(lc,l,mid); if(ri>mid) update(rc,mid+1,r); maintain(o,lc,rc); } inline void solve(){ build(1,1,n); while(Q--){ scanf("%d%d",&pos,&val); le=pos,ri=n,w=val*(ll)ksm(a[pos],ha-2)%ha; a[pos]=val; update(1,1,n); printf("%d\n",sum[1]); } } int main(){ scanf("%d%d",&n,&Q),c[0]=qz[0]=1; for(int i=1;i<=n;i++) c[i]=add(c[i-1],add(c[i-1],c[i-1])); for(int i=1;i<=n;i++){ scanf("%d",a+i); qz[i]=qz[i-1]*(ll)a[i]%ha; } solve(); return 0; }
我爱学习,学习使我快乐