Loj 2028 随机序列

Posted jklover

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Loj 2028 随机序列相关的知识,希望对你有一定的参考价值。

Loj 2028 随机序列

  • 连续的乘号会将序列分成若干个块,块与块之间用加减号连接:

[ (a_1*a_2*...a_i)pm(a_{i+1}*a_{i+2}*...a_j)pm... ]

  • 除去所有都是乘号的一种,对于任意一个序列,总有与之对应唯一的另一个序列,它们所有的加减号都相反.
  • 把这两个序列的和相加,就只剩下了 (2*(a_1*a_2*...a_i)),其中 (i) 为第一个加减号之前的位置.
  • 那么平均下来,相当于每个序列的贡献为 ((a_1*a_2*...a_i)).
  • 考虑对每个 (i) ,前面填入了 (i-1) 个乘号,相邻的必须是加减号,后面 (n-i-1) 个符号随便填,共有 (2*3^{n-i-1}) 种.
  • 那么用线段树对于 ([1,n-1]) 维护 (v_i=3^{n-i-1}*2*prod_{j=1}^i a_i) 的和,答案即为

[ (prod_{i=1}^{n}a_i)+(sum_{i=1}^{n-1}v_i). ]

  • 将位置 (i) 的数从 (a) 改为 (b) ,相当于对区间 ([i,n-1]) 乘了 (frac b a) .显然容易实现.
  • 注意修改位置 (n) 上的数时不用区间修改.否则 (L<R) ,会炸.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            pos=0;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
const int P=1e9+7;
const int MAXN=1e5+10;
const int MAXV=1e4;
int n,m;
inline int add(int a,int b)
{
    return (a + b) % P;
}
inline int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
        {
            if(b&1)
                res=mul(res,a);
            a=mul(a,a);
            b>>=1;
        }
    return res;
}
int inv[MAXV+10],Pow[MAXN];
int a[MAXN],prod[MAXN];
struct node{
    int l,r;
    int sum,tag;
    node()
        {
            tag=1;
        }
}Tree[MAXN<<2];
#define root Tree[o]
#define lson Tree[o<<1]
#define rson Tree[o<<1|1]
void pushup(int o)
{
    root.sum=add(lson.sum,rson.sum);
}
void BuildTree(int o,int l,int r)
{
    root.l=l,root.r=r;
    if(l==r)
        {
            //fpow(3,n-l-1) Pow[n-l-1]
            int tmp=mul(Pow[n-l-1],2);
            tmp=mul(tmp,prod[l]);
            root.sum=tmp;
            return;
        }
    int mid=(l+r)>>1;
    BuildTree(o<<1,l,mid);
    BuildTree(o<<1|1,mid+1,r);
    pushup(o);
}
void Modifiy(int o,int c)
{
    root.sum=mul(root.sum,c);
    root.tag=mul(root.tag,c);
}
void pushdown(int o)
{
    if(root.tag!=1)
        {
            Modifiy(o<<1,root.tag);
            Modifiy(o<<1|1,root.tag);
            root.tag=1;
        }
}
void update(int o,int L,int R,int c)
{
    int l=root.l,r=root.r;
    if(l>R || r<l)
        return;
    if(L<=l && r<=R)
        {
            Modifiy(o,c);
            return;
        }
    pushdown(o);
    int mid=(l+r)>>1;
    if(L<=mid)
        update(o<<1,L,R,c);
    if(R>mid)
        update(o<<1|1,L,R,c);
    pushup(o);
}
void init()
{
    inv[1]=1;
    for(int i=2;i<=MAXV;++i)
        inv[i]=mul(P-P/i,inv[P%i]);
    Pow[0]=1;
    for(int i=1;i<=n;++i)
        Pow[i]=mul(Pow[i-1],3);
}
int main()
{
    n=read(),m=read();
    init();
    prod[0]=1;
    for(int i=1;i<=n;++i)
        prod[i]=mul(prod[i-1],a[i]=read());
    BuildTree(1,1,n-1);
    while(m--)
        {
            int i=read(),v=read();
            int c=mul(v,inv[a[i]]);
            a[i]=v;
            prod[n]=mul(prod[n],c);
            if(i<=n-1)
                update(1,i,n-1,c);
            int ans=add(Tree[1].sum,prod[n]);
            printf("%d
",ans);
        }
    return 0;
}

以上是关于Loj 2028 随机序列的主要内容,如果未能解决你的问题,请参考以下文章

[「COCI 2010.04」KRALJEVI](https://loj.ac/problem/2971)

Loj #2542. 「PKUWC2018」随机游走

loj#2540. 「PKUWC2018」随机算法

loj 2542 随机游走 —— 最值反演+树上期望DP+fmt

[BZOJ5006][LOJ#2290][THUWC2017]随机二分图(概率+状压DP)

loj rounds 补题