【XSY3921】简单的数据结构题(多项式,拉格朗日插值,线段树)

题面

简单的数据结构题

题解

直接考虑我们要计算的式子。为了方便,我们先设 l = 1 , r = n l=1,r=n l=1,r=n

∑ i = 1 n a i k ∏ j ≠ i 1 − a i a j a i − a j = ∑ i = 1 n a i k ( ∏ j ≠ i 1 a i − a j ) ( ∑ l = 0 n − 1 ∑ 1 ≤ j 1 < j 2 < ⋯ < j l ≤ n j 1 , j 2 , ⋯   , j l ≠ i ( − a i a j 1 ) ( − a i a j 2 ) ⋯ ( − a i a j l ) ) = ∑ i = 1 n a i k ( ∏ j ≠ i 1 a i − a j ) ( ∑ l = 0 n − 1 a i l [ x n − 1 − l ] ( ∏ j ≠ i ( x − a j ) ) ) = ∑ l = 0 n − 1 [ x n − 1 − 1 ] ( ∑ i = 1 n a i k + l ∏ j ≠ i x − a j a i − a j ) \begin{aligned} &\sum_{i=1}^na_i^k\prod_{j\neq i}\frac{1-a_ia_j}{a_i-a_j}\\ =&\sum_{i=1}^na_i^k \left(\prod_{j\neq i}\frac{1}{a_i-a_j}\right) \left(\sum_{l=0}^{n-1}\sum_{1\leq j_1<j_2<\cdots<j_l\leq n \atop j_1,j_2,\cdots,j_l\neq i}(-a_ia_{j_1})(-a_ia_{j_2})\cdots(-a_ia_{j_l})\right)\\ =&\sum_{i=1}^na_i^k \left(\prod_{j\neq i}\frac{1}{a_i-a_j}\right) \left(\sum_{l=0}^{n-1} a_i^l[x^{n-1-l}]\left(\prod_{j\neq i}(x-a_j)\right)\right)\\ =&\sum_{l=0}^{n-1}[x^{n-1-1}]\left(\sum_{i=1}^n a_i^{k+l}\prod_{j\neq i}\frac{x-a_j}{a_i-a_j}\right)\\ \end{aligned} ===i=1naikj=iaiaj1aiaji=1naikj=iaiaj1l=0n1j1,j2,,jl=i1j1<j2<<jln(aiaj1)(aiaj2)(aiajl)i=1naikj=iaiaj1l=0n1ail[xn1l]j=i(xaj)l=0n1[xn11]i=1naik+lj=iaiajxaj

发现 ∑ i = 1 n a i k + l ∏ j ≠ i x − a j a i − a j \sum\limits_{i=1}^n a_i^{k+l} \prod\limits_{j\neq i}\frac{x-a_j}{a_i-a_j} i=1naik+lj=iaiajxaj 是拉格朗日插值的形式。

f ( x ) = ∑ i = 1 n a i k + l ∏ j ≠ i x − a j a i − a j f(x)=\sum\limits_{i=1}^n a_i^{k+l} \prod\limits_{j\neq i}\frac{x-a_j}{a_i-a_j} f(x)=i=1naik+lj=iaiajxaj,那么 f ( x ) f(x) f(x) 是恰好经过 ( a 1 , a 1 k + l ) , ( a 2 , a 2 k + l ) , ⋯   , ( a n , a n k + l ) (a_1,a_1^{k+l}),(a_2,a_2^{k+l}),\cdots,(a_n,a_n^{k+l}) (a1,a1k+l),(a2,a2k+l),,(an,ank+l) n n n 个点的小于等于 n − 1 n-1 n1 次的唯一的多项式。注意,满足这个条件的多项式是唯一的,即 f ( x ) f(x) f(x)

考虑构造出 f ( x ) f(x) f(x)

首先注意到 g ( x ) = x k + l g(x)=x^{k+l} g(x)=xk+l 肯定是经过这 n n n 个点的,但它不一定小于等于 n − 1 n-1 n1 次。

然后注意到对于多项式取模 A ( x )   m o d   B ( x ) = C ( x ) A(x) \bmod B(x)=C(x) A(x)modB(x)=C(x) 来说(其中 A ( x ) , B ( x ) , C ( x ) A(x),B(x),C(x) A(x),B(x),C(x) 均为多项式),若有一 x 0 x_0 x0 满足 B ( x 0 ) = 0 B(x_0)=0 B(x0)=0,则 C ( x 0 ) = A ( x 0 )   m o d   B ( x 0 ) = A ( x 0 ) C(x_0)=A(x_0) \bmod B(x_0)=A(x_0) C(x0)=A(x0)modB(x0)=A(x0)。也就是在多项式取模中,若除数是 0 0 0,则商也是 0 0 0,余数和被除数相同。

那么我们设 h ( x ) = g ( x )   m o d   ( x − a 1 ) ( x − a 2 ) ⋯ ( x − a n ) = x k + l   m o d   ( x − a 1 ) ( x − a 2 ) ⋯ ( x − a n ) h(x)=g(x)\bmod (x-a_1)(x-a_2)\cdots(x-a_n)=x^{k+l}\bmod (x-a_1)(x-a_2)\cdots(x-a_n) h(x)=g(x)mod(xa1)(xa2)(xan)=xk+lmod(xa1)(xa2)(xan)。显然,当 x = a i x=a_i x=ai 时,模数是 0 0 0,有 h ( a i ) = g ( a i ) = a i k + l h(a_i)=g(a_i)=a_i^{k+l} h(ai)=g(ai)=aik+l

所以 h ( x ) h(x) h(x) 也是满足 “恰好经过 ( a 1 , a 1 k + l ) , ( a 2 , a 2 k + l ) , ⋯   , ( a n , a n k + l ) (a_1,a_1^{k+l}),(a_2,a_2^{k+l}),\cdots,(a_n,a_n^{k+l}) (a1,a1k+l),(a2,a2k+l),,(an,ank+l) n n n 个点的小于等于 n − 1 n-1 n1 次” 的多项式,而满足这个条件的多项式又是唯一的,所以 h ( x ) = f ( x ) h(x)=f(x) h(x)=f(x)

所以原式转化为:

= ∑ l = 0 n − 1 [ x n − l − 1 ] ( x k + l   m o d   ( x − a 1 ) ( x − a 2 ) ⋯ ( x − a n ) ) =\sum_{l=0}^{n-1}[x^{n-l-1}]\left(x^{k+l}\bmod (x-a_1)(x-a_2)\cdots(x-a_n)\right) =l=0n1[xnl1](xk+lmod(xa1)(xa2)(xan))

注意到 k k k 很小,而 l ≤ n − 1 l\leq n-1 ln1,所以 k + l ≥ n k+l\geq n k+ln 的情况不多,分类讨论即可:

偷一张 solution 的图

在这里插入图片描述

(图片最后一行最后应该是 “ = ( − 1 ) n − 1 ( a 1 + a 2 + ⋯ + a n ) a 1 a 2 ⋯ a n =(-1)^{n-1}(a_1+a_2+\cdots+a_n)a_1a_2\cdots a_n =(1)n1(a1+a2++an)a1a2an”)

于是只需要维护 ∑ i a i \sum\limits_i a_i iai ∏ i a i \prod\limits_i a_i iai ∑ i ∏ j ≠ i a j \sum\limits_{i}\prod\limits_{j\neq i}a_j ij=iaj,在区间乘的操作下用线段树简单维护即可。

代码如下:

#include<bits/stdc++.h>

#define N 300010

using namespace std;

namespace modular
{
	const int mod=998244353;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

struct data
{
	int sum,prod,ans;
	data(){sum=ans=0,prod=1;}
	data(int a,int b,int c){sum=a,prod=b,ans=c;}
}t[N<<2],now;

data merge(data a,data b)
{
	data c;
	c.sum=add(a.sum,b.sum);
	c.prod=mul(a.prod,b.prod);
	c.ans=add(mul(a.prod,b.ans),mul(a.ans,b.prod));
	return c;
}

int n,m,a[N];
int lazy[N<<2];

void up(int k)
{
	t[k]=merge(t[k<<1],t[k<<1|1]);
}

void downn(int k,int l,int r,int val)
{
	int tmp=poww(val,r-l);
	t[k].sum=mul(t[k].sum,val);
	t[k].prod=mul(t[k].prod,mul(tmp,val));
	t[k].ans=mul(t[k].ans,tmp);
	lazy[k]=mul(lazy[k],val);
}

void down(int k,int l,int r,int mid)
{
	if(lazy[k]!=1)
	{
		downn(k<<1,l,mid,lazy[k]);
		downn(k<<1|1,mid+1,r,lazy[k]);
		lazy[k]=1;
	}
}

void build(int k,int l,int r)
{
	lazy[k]=1;
	if(l==r)
	{
		t[k]=data(a[l],a[l],1);
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	up(k);
}

void update(int k,int l,int r,int ql,int qr,int x)
{
	if(ql<=l&&r<=qr)
	{
		downn(k,l,r,x);
		return;
	}
	int mid=(l+r)>>1;
	down(k,l,r,mid);
	if(ql<=mid) update(k<<1,l,mid,ql,qr,x);
	if(qr>mid) update(k<<1|1,mid+1,r,ql,qr,x);
	up(k);
}

void query(int k,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr)
	{
		now=t[k];
		return;
	}
	int mid=(l+r)>>1;
	down(k,l,r,mid);
	data ans;
	if(ql<=mid)
	{
		query(k<<1,l,mid,ql,qr);
		ans=now;
	}
	if(qr>mid)
	{
		query(k<<1|1,mid+1,r,ql,qr);
		ans=merge(ans,now);
	}
	now=ans;
}

int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	build(1,1,n);
	while(m--)
	{
		int opt=read(),l=read(),r=read(),k=read();
		if(opt==1) update(1,1,n,l,r,k);
		else
		{
			int nn=r-l+1,ans=0;
			if(!((nn-k-1)&1)) ans++;
			if(k==1)
			{
				query(1,1,n,l,r);
				if(nn&1) ans=add(ans,now.prod);
				else ans=dec(ans,now.prod);
			}
			if(k==2)
			{
				query(1,1,n,l,r);
				if(nn&1) ans=dec(ans,now.ans);
				else ans=add(ans,now.ans);
				int tmp=mul(now.sum,now.prod);
				if(nn&1) ans=add(ans,tmp);
				else ans=dec(ans,tmp);
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}
/*
3 3
1 2 3
2 1 2 0
1 1 3 5
2 1 2 0
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值