【bzoj4597】[Shoi2016]随机序列 线段树

像我这种在SDOI考场上连普及组难度的题都A不掉的人活该滚粗,能解决问题的方法那么多,为什么我非要写 那个最慢的高精度?用自己水的一比的极限数据测了一下,就自信的交了?

不要被什么乱七八糟的求和给吓到了,实际上一加一减全抵消了,因为第一个数的符号永远为+,所以剩下的都是跟第一个数有关的,即前缀乘积。

sum[i]=a[1]*a[2]*……*a[i],考虑sum[i]对答案的贡献,sum[i]后面的符号不能是×,剩下的符号随便选,所以总共要计算2*3^(n-i-1)次。特别地,sum[n]只计算一次。

然后就是修改,线段树维护前缀乘积,每次修改对应修改一个后缀,预处理出逆元,就是随便做了。


#include
#include
#include
#include
#include
#include
#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


你可能感兴趣的:(数据结构)