题面
题解
直接考虑我们要计算的式子。为了方便,我们先设 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=1∑naikj=i∏ai−aj1−aiaji=1∑naik⎝⎛j=i∏ai−aj1⎠⎞⎝⎜⎛l=0∑n−1j1,j2,⋯,jl=i1≤j1<j2<⋯<jl≤n∑(−aiaj1)(−aiaj2)⋯(−aiajl)⎠⎟⎞i=1∑naik⎝⎛j=i∏ai−aj1⎠⎞⎝⎛l=0∑n−1ail[xn−1−l]⎝⎛j=i∏(x−aj)⎠⎞⎠⎞l=0∑n−1[xn−1−1]⎝⎛i=1∑naik+lj=i∏ai−ajx−aj⎠⎞
发现 ∑ 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=1∑naik+lj=i∏ai−ajx−aj 是拉格朗日插值的形式。
设 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=1∑naik+lj=i∏ai−ajx−aj,那么 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 n−1 次的唯一的多项式。注意,满足这个条件的多项式是唯一的,即 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 n−1 次。
然后注意到对于多项式取模 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(x−a1)(x−a2)⋯(x−an)=xk+lmod(x−a1)(x−a2)⋯(x−an)。显然,当 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 n−1 次” 的多项式,而满足这个条件的多项式又是唯一的,所以 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=0∑n−1[xn−l−1](xk+lmod(x−a1)(x−a2)⋯(x−an))
注意到 k k k 很小,而 l ≤ n − 1 l\leq n-1 l≤n−1,所以 k + l ≥ n k+l\geq n k+l≥n 的情况不多,分类讨论即可:
偷一张 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)n−1(a1+a2+⋯+an)a1a2⋯an”)
于是只需要维护 ∑ i a i \sum\limits_i a_i i∑ai、 ∏ i a i \prod\limits_i a_i i∏ai 和 ∑ i ∏ j ≠ i a j \sum\limits_{i}\prod\limits_{j\neq i}a_j i∑j=i∏aj,在区间乘的操作下用线段树简单维护即可。
代码如下:
#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
*/