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\n",ans);
		}
	return 0;
}

相关文章:

  • 2021-09-14
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-15
  • 2021-11-30
  • 2021-10-07
  • 2022-12-23
猜你喜欢
  • 2021-11-23
  • 2021-06-17
  • 2022-02-25
  • 2021-12-23
  • 2021-11-13
  • 2022-03-10
  • 2021-09-26
相关资源
相似解决方案