P4340 [SHOI2016]随机序列(线段树)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4340 [SHOI2016]随机序列(线段树)相关的知识,希望对你有一定的参考价值。
P4340 [SHOI2016]随机序列(线段树)
结论:
只有前缀积有贡献。
因为第一个数前面是没有符号的,除了前缀积外,都可以通过加号变成减号、减号变加号使其贡献抵消。
接下来考虑每个前缀积的贡献。
我们可以枚举前缀积的位置 i i i。
记录前缀积为 s i s_i si,第 i i i个符号可以有两种选择 + , − +,- +,−。
然后其他符号任意选。
所以一共有: 2 × 3 n − i − 1 2\\times 3^{n-i-1} 2×3n−i−1
然后总和就是:
a n s = ∑ i = 1 n − 1 s i × 2 × 3 n − i − 1 + s n \\large ans=\\sum\\limits_{i=1}^{n-1}s_i\\times 2\\times 3^{n-i-1}+s_n ans=i=1∑n−1si×2×3n−i−1+sn
这里可以预处理每个 i i i对应的答案,然后修改 a i a_i ai就是相当于后缀区间乘法。
因为有模,所以要预处理逆元,但是 a i a_i ai非负, 0 0 0不存在逆元。所以此方法不可行。
考虑维护两个变量区间和 s s s 和区间 a i a_i ai的乘积 m m m
然后更新的话就是: a m = l s o n m + r s o n m , a s = l s o n s + r s o n s × l s o n m a_m=lson_m+rson_m,a_s=lson_s+rson_s\\times lson_m am=lsonm+rsonm,as=lsons+rsons×lsonm
// Problem: P4340 [SHOI2016]随机序列
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4340
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// Date: 2021-08-18 17:17:09
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
int n,q;
//区间修改 区间求和
#define il inline
#define lx x<<1
#define rx x<<1|1
#define len(x) (a[x].r-a[x].l+1)
struct node{
int l,r,lz;
ll s,m;
}a[N<<2];
int p[N],w[N];
il void re(int x){
a[x].m=a[lx].m*a[rx].m%mod;
a[x].s=(a[lx].s+a[rx].s*a[lx].m%mod)%mod;
}
il void bud(int x,int l,int r){
a[x].l=l,a[x].r=r;
if(l==r){
a[x].m=w[l];
a[x].s=l<n?w[l]*2LL*p[n-l-1]%mod:w[n];
return;
}
int m=(l+r)>>1;bud(lx,l,m),bud(rx,m+1,r);
re(x);
}
il void upd(int x,int pos,int v){
if(a[x].l==a[x].r){
a[x].m=w[pos]=v;
a[x].s=a[x].l<n?v*2LL*p[n-pos-1]%mod:v;return;
}
int m=a[x].l+a[x].r>>1;
if(pos<=m) upd(lx,pos,v);
else upd(rx,pos,v);
re(x);
}
int main(){
scanf("%d%d",&n,&q);p[0]=1;
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
p[i]=p[i-1]*3LL%mod;
}
bud(1,1,n);
while(q--){
int p,v;scanf("%d%d",&p,&v);
upd(1,p,v);
printf("%lld\\n",a[1].s);
}
return 0;
}
以上是关于P4340 [SHOI2016]随机序列(线段树)的主要内容,如果未能解决你的问题,请参考以下文章