bzoj4597 [Shoi2016]随机序列

来源:互联网 发布:大数据的工资待遇 编辑:程序博客网 时间:2024/05/22 05:34

【题意】

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 1000000007using namespace std; struct tt{int a, b, l, r, s, f;}t[N*2];int n, m, w[N], bin[N], v[N], now, l, inv[N], 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;}


0 0
原创粉丝点击