像我这种在SDOI考场上连普及组难度的题都A不掉的人活该滚粗,能解决问题的方法那么多,为什么我非要写 那个最慢的高精度?用自己水的一比的极限数据测了一下,就自信的交了?
不要被什么乱七八糟的求和给吓到了,实际上一加一减全抵消了,因为第一个数的符号永远为+,所以剩下的都是跟第一个数有关的,即前缀乘积。
sum[i]=a[1]*a[2]*……*a[i],考虑sum[i]对答案的贡献,sum[i]后面的符号不能是×,剩下的符号随便选,所以总共要计算2*3^(n-i-1)次。特别地,sum[n]只计算一次。
然后就是修改,线段树维护前缀乘积,每次修改对应修改一个后缀,预处理出逆元,就是随便做了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define mod 1000000007
#define maxn 100010
using namespace std;
struct yts
{
int l,r;
long long sum,tag;
}t[4*maxn];
long long a[maxn],inv[10010],sum[maxn];
int n,m,T;
long long power(long long x,int y)
{
long long ans=1;
while (y)
{
if (y&1) ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
void build(int i,int l,int r)
{
t[i].l=l;t[i].r=r;t[i].tag=1;
if (l==r) {if (l!=n) t[i].sum=(2ll*power(3,n-l-1)%mod)*sum[l]%mod; else t[i].sum=sum[n];return;}
int mid=(l+r)/2;
build(i*2,l,mid);build(i*2+1,mid+1,r);
t[i].sum=(t[i*2].sum+t[i*2+1].sum)%mod;
}
void add(int i,long long x)
{
t[i].tag=t[i].tag*x%mod;
t[i].sum=t[i].sum*x%mod;
}
void release(int i)
{
if (t[i].l==t[i].r || !t[i].tag) return;
add(i*2,t[i].tag);add(i*2+1,t[i].tag);
t[i].tag=1;
}
void modify(int i,int l,int r,long long x)
{
if (l<=t[i].l && t[i].r<=r) {add(i,x);return;}
release(i);
int mid=(t[i].l+t[i].r)/2;
if (l<=mid) modify(i*2,l,r,x);
if (mid<r) modify(i*2+1,l,r,x);
t[i].sum=(t[i*2].sum+t[i*2+1].sum)%mod;
}
int main()
{
for (int i=1;i<=10000;i++) inv[i]=power(i,mod-2);
scanf("%d%d",&n,&T);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
sum[0]=1;
for (int i=1;i<=n;i++) sum[i]=sum[i-1]*a[i]%mod;
build(1,1,n);
while (T--)
{
int pos;
long long x;
scanf("%d%lld",&pos,&x);
modify(1,pos,n,inv[a[pos]]*x%mod);
a[pos]=x;
printf("%lld\n",t[1].sum);
}
return 0;
}