您的位置:首页 > 其它

bzoj4597 [Shoi2016]随机序列

2016-12-18 23:14 387 查看
【题意】

n个数,任意相邻两数之间加入“+”“-”“*”三种符号中的一种,数列的答案即为这3^(n-1)种表达式的和mod(10^9+7)的值。

m次修改,每次修改一个数并求出数列的答案。

【数据范围】

n<=100000,m<=100000,1<=数列中的数<=10000

【思路】

设w=10000。

定义一个区间[L,R]中的符号均为“*”,且L前与R后的符号不为“*”。

由于“+”“-”可相互抵消,对于所有L>=2的区间,L前面的符号不为“*”(定义),“+”“-”次数相同,故这样的区间对答案贡献为0。

故答案由若干L=1的区间计算得到:

若L=1且R=n,后面没有符号位,故它对答案贡献1次。

若L=1且R<n,后面的符号任意填,故共有2*3^(n-R-1)种填法,贡献2*3^(n-R-1)次。

每次修改相当于一个后缀区间/原数*现数,/原数相当于*原数的逆元,逆元可预处理得到。故问题变为维护区间修改(乘一个数),整体求和,裸线段树。

【时间复杂度】

O((n+m) log n+w log (10^9+7))

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100010
#define ll long long
#define mod 1000000007
using namespace std;

struct tt{int a, b, l, r, s, f;}t[N*2];
int n, m, w
, bin
, v
, now, l, inv
, x, y, z;

inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}

int pow(int y, int x){
int s=1, t=y;
while(x){
if(x&1)s=(ll)s*t%mod;
t=(ll)t*t%mod; x>>=1;
}
return s;
}

void update(int i){
t[i].s=(t[t[i].l].s+t[t[i].r].s)%mod;
}
void maketree(int L, int R){
t[l].a=L; t[l].b=R; t[l].l=t[l].r=t[l].s=0; t[l].f=1;
if(L<R){
int mid=(L+R)>>1, l1=l;
l++; t[l1].l=l; maketree(L, mid);
l++; t[l1].r=l; maketree(mid+1, R);
update(l1);
}else t[l].s=v[L];
}
void pushdown(int i){
if(t[i].f>1){
t[t[i].l].f=(ll)t[t[i].l].f*t[i].f%mod;
t[t[i].l].s=(ll)t[t[i].l].s*t[i].f%mod;
t[t[i].r].f=(ll)t[t[i].r].f*t[i].f%mod;
t[t[i].r].s=(ll)t[t[i].r].s*t[i].f%mod;
t[i].f=1;
}
}
void ins(int i, int a, int b, int c){
if(a<=t[i].a&&t[i].b<=b){
t[i].f=(ll)t[i].f*c%mod; t[i].s=(ll)t[i].s*c%mod;
return;
}
pushdown(i);
int mid=(t[i].a+t[i].b)>>1;
if(a<=mid)ins(t[i].l, a, b, c);
if(mid<b)ins(t[i].r, a, b, c);
update(i);
}

int main(){
n=read(); m=read();
for(int i=1; i<=n; i++)w[i]=read();
bin[0]=2;
for(int i=1; i<=n; i++)bin[i]=(ll)bin[i-1]*3%mod;
for(int i=0; i<=10000; i++)inv[i]=pow(i, mod-2);
now=1;
for(int i=1; i<=n; i++){
now=(ll)now*w[i]%mod;
if(i<=n-1)v[i]=(ll)now*bin[n-i-1]%mod; else v[i]=now;
}
l=1; maketree(1, n);
for(int i=1; i<=m; i++){
x=read(); y=read();
z=(ll)inv[w[x]]*y%mod; w[x]=y;
ins(1, x, n, z); printf("%d\n", t[1].s);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: