洛谷7111

第一次想出多项式题。
其实去年就想出来了,今年再推一遍。
考虑一个式子,\([x^y]\prod_{i=1}^n(1+x+x^2+...+x^{a_i})\)
注意到后面和\(\frac{1}{1-x}\)长得很像,所以把后面的\(1+x+x^2+...+x^{a_i}\)拆成\((1+x+x^2+....)-(x^{a_i+1}+....)=\frac{1-x^{a_i+1}}{1-x}\)
\(b_i=a_i+1\)原式\(=[x^y]\prod_{i=1}^n(\frac{1-x^{b_i}}{1-x})\)
考虑询问怎么求。
注意到在一次询问内,无论\(b_i\)改成多少,\(\frac{1}{1-x}\)的次数永远是\(n\)
\(p(x)=\prod_{i=1}^n\frac{1-x^{b_i}}{1-x}\)
先把\(p(x)\)乘以\(\frac{1}{1-x}\)表示取前缀和。
所以询问要我们求的:\([x^y]p(x)\frac{1-x^z}{1-x^{b_i}}\),其中\(z\)是原题的\(x+1\)
把下面展开,就是要我们求\([x^y]p(x)(1-x^z)(1+x^{b_i}+x^{2b_i}+.....)\)
枚举\((1-x^z)\)取哪个项,则问题转化成\(O(q)\)组询问:\(p(x)(1+x^{b_i}+x^{2b_i}+.....)\)的某项系数。
实际上就是哈希冲突。
\(b_i\geq \sqrt{10^5}\),由于询问系数是\(O(10^5)\)级别,可以暴力计算。
\(b_i<\sqrt{10^5}\),由于可能的\(b_i\)只有\(O(\sqrt{10^5})\)种,可以预处理出每种\(b\)的答案。
\(f_{i,j}\)表示\(y=i,b_i=j\)的答案,可以递推求。
\([x^y]1-x^{b_i}\)是个经典问题(付公主的背包),求出\((\frac{1}{1-x})^{n+1}\)可以按照生成函数的定义。
然后把\([x^y]1-x^{b_i}\)乘以\((\frac{1}{1-x})^{n+1}\)就是\(p\)
最终时间复杂度\(O(n\sqrt{n})\)
感觉没什么细节,但是不知道为啥调了这么久

#include<bits/stdc++.h>
using namespace std;
#define mo 998244353
#define N 500010
#define ll unsigned long long
#define int long long
#define pl vector<int>
int qp(int x,int y){
	int r=1;
	for(;y;y>>=1,x=1ll*x*x%mo)
		if(y&1)r=1ll*r*x%mo;
	return r;
}
int rev[N],v,le,w[N];
void deb(pl x){
	for(int i=0;i<x.size();i++)
		printf("%lld ",x[i]);
	puts("");
}
void init(int n){
	v=1;
	le=0;
	while(v<n)le++,v*=2;
	for(int i=0;i<v;i++)
		rev[i]=(rev[i>>1]>>1)|((i&1)<<(le-1));
	int g=qp(3,(mo-1)/v);
	w[v/2]=1;
	for(int i=v/2+1;i<v;i++)
		w[i]=1ull*w[i-1]*g%mo;
	for(int i=v/2-1;~i;i--)
		w[i]=w[i*2];
}
void fft(int v,pl &a,int t){
	static unsigned long long b[N];
	int s=le-__builtin_ctz(v);
   	for(int i=0;i<v;i++)
   		b[rev[i]>>s]=a[i];
	int c=0;
	w[0]=1;
    for(int i=1;i<v;i*=2,c++)
    	for(int r=i*2,j=0;j<v;j+=r)
            for(int k=0;k<i;k++){
               	int tx=b[j+i+k]*w[k+i]%mo;
            	b[j+i+k]=b[j+k]+mo-tx;
            	b[j+k]+=tx;
            }
    for(int i=0;i<v;i++)
    	a[i]=b[i]%mo;
    if(t==0)return;
    int iv=qp(v,mo-2);
    for(int i=0;i<v;i++)
    	a[i]=1ull*a[i]*iv%mo;
    a.resize(v);
    reverse(a.begin()+1,a.end());
}
pl operator *(pl x,pl y){
	int s=x.size()+y.size()-1;
	if(x.size()<=20||y.size()<=20){
		pl r;
		r.resize(s);
		for(int i=0;i<x.size();i++)
			for(int j=0;j<y.size();j++)
				r[i+j]=(r[i+j]+x[i]*y[j])%mo;
		return r;
	}
	init(s);
	x.resize(v);
	y.resize(v);
	fft(v,x,0);
	fft(v,y,0);
	//deb(x);
	//deb(y);
	for(int i=0;i<v;i++)
		x[i]=x[i]*y[i]%mo;
	fft(v,x,1);
	x.resize(s);
	return x;
}
void inv(int n,pl &b,pl &a){
	if(n==1){
		b[0]=qp(a[0],mo-2);
		return;
	}
	inv((n+1)/2,b,a);
    static pl c;
	init(n*2);
	c.resize(v);
	b.resize(v);
    for(int i=0;i<n;i++)
		c[i]=a[i];
    fft(v,c,0);
    //deb(c);
	fft(v,b,0);
	//deb(b);
    for(int i=0;i<v;i++)
    	b[i]=1ll*(2ll-1ll*c[i]*b[i]%mo+mo)%mo*b[i]%mo;
    //deb(b);
    fft(v,b,1);  
   	b.resize(n);
   	//deb(b);
}
void ad(pl &x,pl y,int l){
	x.resize(max((int)x.size(),(int)y.size()+l));
	for(int i=0;i<y.size();i++)
		x[i+l]=(x[i+l]+y[i])%mo;
}
pl operator +(pl x,pl y){
	ad(x,y,0);
	return x;
}
pl iv(pl x){
	pl y;
	int n=x.size();
	y.resize(n);
	inv(n,y,x);
	y.resize(n);
	return y;
}
pl operator -(pl x,pl y){
	int s=max(x.size(),y.size());
	x.resize(s);
	y.resize(s);
	for(int i=0;i<s;i++)
		x[i]=(x[i]-y[i]+mo)%mo;
	return x;
}
pl qd(pl x){
	pl y;
	int n=x.size();
	y.resize(n-1);
	//deb(x);
	for(int i=0;i<n-1;i++)
		y[i]=x[i+1]*(i+1)%mo;
	//deb(y);
	return y;
}
pl jf(pl x){
	int n=x.size();
	pl y;
	y.resize(n+1);
	for(int i=1;i<=n;i++)
		y[i]=x[i-1]*qp(i,mo-2)%mo;
	return y;
}
pl ln(pl x){
	int n=x.size();
	pl y=qd(x),z=iv(x);
	y=y*z;
	y=jf(y);
	y.resize(n);
	return y;
}
char bf[100];
void wr(int x){
	if(!x){
		putchar('0');
		putchar(' ');
		return;
	}
    int ct=0;
    while(x){
        bf[++ct]=x%10;
        x/=10;
    }
    for(int i=ct;i;i--)
        putchar(bf[i]+'0');
    putchar('\n');
}
void gt(int n,pl &y,pl x){
	if(n==1){
		y.resize(1);
		y[0]=1;
		return;
	}
	gt((n+1)/2,y,x);
	pl z=x,a;
	z.resize(n);
	y.resize(n);
	a.resize(1);
	a[0]=1;
	y=y*(a-ln(y)+z);
	y.resize(n);
}
pl ep(pl x){
	pl y;
	int n=x.size();
	gt(n,y,x);
	return y;
}
void put(pl a){
	for(int i=0;i<a.size();i++)
		printf("%lld ",a[i]);
	puts("");
}
int n,a[N],q,ii[N],c[N],jc[N],ij[N];
signed g[N/5+10][400];
pl f;
void gt(int m){
	f.resize(m+1);
	for(int i=1;i<=m;i++)
		for(int j=i;j<=m;j+=i)
			f[j]=(f[j]+c[i]*(mo-ii[j/i]))%mo;
	f=ep(f);
}
int cc(int y,int x){
	return jc[y]*ij[x]%mo*ij[y-x]%mo;
}
int qu(int a,int b){
	if(a<0)
		return 0;
	if(b<400)
		return g[a][b];
	else{
		int ans=0;
		for(int j=a;j>=0;j-=b)
			ans=(ans+f[j])%mo;
		return ans;
	}
}
signed main(){
	jc[0]=ij[0]=1;
	for(int i=1;i<N;i++){
		ii[i]=qp(i,mo-2);
		jc[i]=jc[i-1]*i%mo;
	}
	ij[N-1]=qp(jc[N-1],mo-2);
	for(int i=N-1;i;i--)
		ij[i-1]=ij[i]*i%mo;
	scanf("%lld%lld",&n,&q);
	int va=1;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		a[i]++;
		va=va*a[i]%mo;
	}
	pl d;
	d.resize(100010);
	for(int i=0;i<100010;i++)
		d[i]=cc(n+i,n);
	for(int i=1;i<=n;i++)
		c[a[i]]++;
	gt(100010);
	f=f*d;
	for(int j=1;j<400;j++)
		for(int i=0;i<100010;i++){
			if(i>=j)
				g[i][j]=(g[i-j][j]+f[i])%mo;
			else
				g[i][j]=f[i];
		}
	for(int i=1;i<=q;i++){
		int p,x,y,ans=0;
		scanf("%lld%lld%lld",&p,&x,&y);
		y--;
		x++;
		ans=(ans+qu(y,a[p]))%mo;
		ans=(ans-qu(y-x,a[p])+mo)%mo;
		int vv=va*ii[a[p]]%mo*x%mo,vs=vv;
		vs=(vs-ans+mo)%mo;
		printf("%lld\n",vs*qp(vv,mo-2)%mo);
	}
}
posted @ 2021-02-23 15:47  celerity1  阅读(45)  评论(0编辑  收藏  举报