设一个人被扣了 \(i\) 滴血的概率为 \(p_i\),设 \(c_i=exp-i\) 且只有 \(c_0,c_1,\cdots,c_{exp}\) 有值,那么题目就是在问 \(\sum\limits_{i=0}^{exp}c_ip_i\)。
我们设 \(p_i\) 的生成函数为 \(P(x)\),那么第 \(i\) 次操作相当于将 \(P(x)\) 乘上 \((p_ix+(1-p_i))\)。
那么题目第 \(t\) 次询问要求的即为 \(\sum\limits_{i=0}^{exp}c_i[x^i]P(x)\),其中 \(P(x)=\prod\limits_{i=1}^t(p_ix+(1-p_i))\)。
每次求出 \(P(x)\) 并暴力统计答案显然是不现实的。
设 \(P(x)=A(x)B(x)\),\(A(x)=\prod\limits_{i=1}^k(p_ix+(1-p_i))=\sum\limits_{i=0}^ka_ix^i\),\(B(x)=\prod\limits_{i=k+1}^{t}(p_ix+(1-p_i))=\sum\limits_{i=0}^{t-k}b_ix^i\)。
那么:
\[\begin{aligned} ans_t&=\sum\limits_{i=0}^{exp}c_i[x^i]P(x)\\ &=\sum_{i=0}^{exp}c_i[x^i]A(x)B(x)\\ &=\sum_{i=0}^{exp}c_i\sum_{j=0}^ia_jb_{i-j}\\ &=\sum_{i=0}^{exp}b_i\sum_{j=0}^{exp-i}c_{j+i}a_j\\ &=\sum_{i=0}^{exp}c_i'[x^i]B(x) \end{aligned} \](其中 \(c_i'=\sum\limits_{j=0}^{exp-i}c_{j+i}a_j\))
然后就可以分治了:假设当前区间为 \([l,r]\),长度为 \(m=r-l+1\),我们可以先递归 \([l,mid]\),算出这段区间的答案,并算出次数为 \(\dfrac{m}{2}\) 的 \(A(x)\),再用它和 \(c_i\) 做减法卷积 \(O(m\log m)\) 算出 \(c_i'\) 的前 \(\dfrac{m}{2}\) 项,然后再把 \(c_i'\) 代入作为新的 \(c_i\) 递归 \([mid+1,r]\),算出这段区间的答案,并算出次数为 \(\dfrac{m}{2}\) 的 \(B(x)\),最后 \(O(m\log m)\) 计算出 \(P(x)=A(x)B(x)\)。
总时间复杂度 \(O(n\log^2n)\)。
#include<bits/stdc++.h>
#define LN 19
#define N 100010
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;
}
typedef vector<int> poly;
int lans,n;
int rev[N<<2],w[LN][N<<2][2];
int A[N<<2],B[N<<2];
poly p[N<<2],c[N<<2];
void init(int limit)
{
for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
{
int len=mid<<1;
int gn=poww(3,(mod-1)/len);
int ign=poww(gn,mod-2);
int g=1,ig=1;
for(int j=0;j<mid;g=mul(g,gn),ig=mul(ig,ign),j++)
w[bit][j][0]=g,w[bit][j][1]=ig;
}
}
void NTT(int *a,int limit,int opt)
{
opt=(opt<0);
for(int i=0;i<limit;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)*(limit>>1));
for(int i=0;i<limit;i++)
if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
{
for(int i=0,len=mid<<1;i<limit;i+=len)
{
for(int j=0;j<mid;j++)
{
int x=a[i+j],y=mul(w[bit][j][opt],a[i+mid+j]);
a[i+j]=add(x,y),a[i+mid+j]=dec(x,y);
}
}
}
if(opt)
{
int tmp=poww(limit,mod-2);
for(int i=0;i<limit;i++)
a[i]=mul(a[i],tmp);
}
}
void solve(int k,int l,int r)
{
if(l==r)
{
int pi=read();
pi=add(pi,lans);
p[k].push_back(dec(1,pi));
p[k].push_back(pi);
printf("%d\n",lans=(add(mul(p[k][0],c[k][0]),mul(p[k][1],c[k][1]))));
return;
}
int mid=(l+r)>>1,lc=k<<1,rc=k<<1|1;
int len=r-l+1,lenl=mid-l+1,lenr=r-mid;
for(int i=0;i<=lenl;i++) c[lc].push_back(c[k][i]);
solve(lc,l,mid);
int limit=1;
while(limit<=len+lenl) limit<<=1;
for(int i=0;i<=len;i++) A[i]=c[k][i];
for(int i=0;i<=lenl;i++) B[i]=p[lc][lenl-i];
NTT(A,limit,1),NTT(B,limit,1);
for(int i=0;i<limit;i++) A[i]=mul(A[i],B[i]);
NTT(A,limit,-1);
for(int i=0;i<=lenr;i++) c[rc].push_back(A[lenl+i]);
for(int i=0;i<limit;i++) A[i]=B[i]=0;
solve(rc,mid+1,r);
limit=1;
while(limit<=len) limit<<=1;
for(int i=0;i<=lenl;i++) A[i]=p[lc][i];
for(int i=0;i<=lenr;i++) B[i]=p[rc][i];
NTT(A,limit,1),NTT(B,limit,1);
for(int i=0;i<limit;i++) A[i]=mul(A[i],B[i]);
NTT(A,limit,-1);
for(int i=0;i<=len;i++) p[k].push_back(A[i]);
for(int i=0;i<limit;i++) A[i]=B[i]=0;
}
int main()
{
lans=read(),n=read();
int limit=1;
while(limit<=(n<<1)) limit<<=1;
init(limit);
for(int i=0;i<=lans;i++) c[1].push_back(lans-i);
for(int i=lans+1;i<=n;i++) c[1].push_back(0);
solve(1,1,n);
return 0;
}
/*
1 1
0
*/
/*
918 991
456307063
488721210
886185325
243931909
217329246
856712605
*/
/*
98908 99965
775551600
543754136
259120750
821986384
362863140
*/
标签:ix,ch,limits,int,sum,暴风,XSY3241,exp,stormtrooper
From: https://www.cnblogs.com/ez-lcw/p/16840744.html