zoukankan      html  css  js  c++  java
  • [SHOI2016] 随机序列

    4597: [Shoi2016]随机序列

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 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

    Sample Output

    890543652
    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
    ",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
    ",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;
    }
    

      

     
  • 相关阅读:
    蚂蚁问题
    LinuxC安装gcc
    怎样在VC里面使用graphics.h绘图
    C语言之固定格式输出当前时间
    C语言之猜数字游戏
    C语言之新同学年龄
    C语言之ASCII码
    C语言之辗转相除法
    C语言之自守数
    C语言之一数三平方
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8654283.html
Copyright © 2011-2022 走看看