P4705 玩游戏 解题报告

原题链接

不是都写得什么 jb 常数,我交了三发都是最优解,还看不了别人代码,恼火。

不算很难,反正推式子都挺套路的,但是取 \(ln\) 非常nb。

对于每一个 \(k\)\(ans_k=\frac{\sum\limits_{i=1}^n\sum\limits_{j=1}^m(a_i+b_j)^k}{nm}\),考虑分母上的式子。

\[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^m(a_i+b_j)^k&=\sum_{i=1}^n\sum_{j=1}^m\sum_{p=0}^k\mathrm{C}_{k}^pa_i^pb_j^{k-p}\\ &=k!\sum_{i=1}^n\sum_{j=1}^m\sum_{p=0}^k\frac{a_i^p}{p!}\frac{b_j^{k-p}}{(k-p)!}\\ &=k!\sum_{p=0}^k(\sum_{i=1}^n\frac{a_i^p}{p!})(\sum_{j=1}^m\frac{b_j^{k-p}}{(k-p)!}) \end{aligned}\]

发现这是一个卷积的形式,那么现在就考虑如何快速求出分母上的那个,即 \(\sum\limits_{i=1}^na_i^p\)

先只考虑一个元素,显然其生成函数 \(A(x)=\frac{1}{1-ax}\)。然后设 \(F(x)\) 表示这些生成函数的和,即 \(F(x)=\sum\limits_{i=1}^n\frac{1}{1-a_ix}\)

还是经典的考虑对数,发现 \([\ln(1-ax)]^\prime=\frac{-a}{1-ax}\),于是设 \(G(x)=\sum\limits_{i=1}^n\frac{-a_i}{1-a_ix}\),然后就有 \(F(x)=-xG(x)+n\),考虑都拆成无穷级数的形式得证。

现在就是考虑如何算 \(G(x)\)

\[\begin{aligned} G(x)&=\sum_{i=1}^n[\ln(1-a_ix)]^\prime\\ &=(ln(\prod_{i=1}^n(1-a_ix)))^\prime \end{aligned}\]

后面的式子直接分治求乘法就好了,时间复杂度 \(O(n\log^2n)\)

如果想不到 \(ln\),也可以学习神鱼的暴力做法。

\[\frac{A(x)}{B(x)}+\frac{C(x)}{D(x)}=\frac{A(x)D(x)+B(x)C(x)}{B(x)D(x)} \]

然后分治求加法即可,常数\(++++++++++\)

AC Link

AC code
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
  auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
  auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
namespace PolyBasedNTT{
#define IL inline
  const int _N = 4e5 + 10;
  const int _P = 998244353;
  const int _G = 3,_Gi = 332748118;
  using poly = vector<int>;
  int _t[_N];poly rt[22];
  int lastnnn = 0,lastlim = 0;
  poly invn;int lastinvn = 0;
  template<class T> T FMod(const T &x){return x >= _P?x-_P:x;}
  IL void _invpre(){
    invn.resize(_N-9);invn[1] = 1;
    for(int i = 2;i <= _N-10; ++i) invn[i] = 1ll*invn[_P%i]*(_P-_P/i)%_P;
  }
  IL int qpow(int a,int b,int Mod = _P){
    int res = 1;
    for(;b;b >>= 1,a = 1ll*a*a%Mod)
      if(b&1) res = 1ll*res*a%Mod;
    return res;
  }
  IL int invi(int a){return qpow(a,_P-2);}
  IL void Poly_pre(){
    rt[0].resize(1,1);int pp = __lg(_N);
    for(int i = 1;i < pp; ++i){
      poly &g = rt[i];g.resize(1<<i,1);
      const int t = qpow(_G,_P>>(i+1));
      for(int j = 1;j < (1<<i); ++j) g[j] =1ll*g[j-1]*t%_P;
    }
  }
  IL int _prepare(int n){
    if(lastnnn == n) return lastlim;
    lastnnn = n;int lim = 1,ct = -1;
    while(lim < n) lim <<= 1,ct++;
    for(int i = 0;i < lim; ++i) _t[i] = (_t[i>>1]>>1)|((i&1)<<ct);
    return (lastlim = lim);
  }
  IL void NTT(poly &a,int n,bool type = true){
    n = _prepare(n);a.resize(n);
    for(int i = 1;i < n; ++i) if(i < _t[i]) swap(a[i],a[_t[i]]);
    for(int mid = 1,now = 0;mid < n;mid <<= 1, ++now){
      auto &G = rt[now];
      for(int Res = mid << 1,j = 0;j < n;j += Res){
        for(int k = 0;k < mid; ++k){
          int x = a[j+k],y = 1ll*G[k]*a[j+k+mid]%_P;
          a[j+k] = FMod(x + y);
          a[j+k+mid] = FMod(x - y + _P);
        }
      }
    }
    if(!type) reverse(a.begin()+1,a.end());
  }
  IL void rev(poly &a){reverse(a.begin(),a.end());}
  IL poly operator * (poly a,poly b){
    int lena = a.size(),lenb = b.size();
    if(lena <= 50 && lenb <= 50){
      poly res(lena+lenb-1);
      for(int i = 0;i < lena; ++i) for(int j = 0;j < lenb; ++j)
        res[i+j] = FMod(res[i+j] + 1ll*a[i]*b[j]%_P);
      return res;
    }
    int len = lena+lenb,Len = _prepare(len),llen = invi(Len);
    NTT(a,len);NTT(b,len);
    for(int i = 0;i < Len; ++i) a[i] = 1ll*a[i]*b[i]%_P;
    NTT(a,len,false);
    for(int i = 0;i < len; ++i) a[i] = 1ll*a[i]*llen%_P;
    a.resize(len-1);
    return a;
  }
  IL poly operator + (poly a,poly b){
    int lena = a.size(),lenb = b.size();
    int len = max(lena,lenb);
    poly res(len);
    for(int i = 0;i < lena; ++i) res[i] = FMod(res[i] + a[i]);
    for(int i = 0;i < lenb; ++i) res[i] = FMod(res[i] + b[i]);
    return res;
  }
  IL poly operator - (poly a,poly b){
    int lena = a.size(),lenb = b.size(),len = max(lena,lenb);
    poly res(len);
    for(int i = 0;i < lena; ++i) res[i] = FMod(res[i] + a[i]);
    for(int i = 0;i < lenb; ++i) res[i] = FMod(res[i] - b[i] + _P);
    return res;
  }
  poly invp(poly x,int n){
    if(n == 1) return {invi(x[0])};
    poly y = invp(poly(x.begin(),x.begin()+((n+1)>>1)),(n+1)>>1);
    int len = _prepare(n<<1);
    NTT(x,n<<1);NTT(y,n<<1);
    for(int i = 0;i < len; ++i) x[i] = 1ll*y[i]*FMod(2-1ll*x[i]*y[i]%_P+_P)%_P;
    NTT(x,n<<1,false);int llen = invi(len);
    for(int i = 0;i < len; ++i) x[i] = 1ll*x[i]*llen%_P;
    x.resize(n);
    return x;
  }
  IL poly operator / (poly x,poly y){
    int n = x.size(),m = y.size(),len = n - m + 1;
    rev(x);rev(y);y.resize(len);
    poly res = x*invp(y,len);
    res.resize(len);rev(res);
    return res;
  }
  IL poly operator % (poly x,poly y){
    poly res = x - (x/y)*y;
    res.resize(y.size()-1);
    return res;
  }
  IL poly Diff(poly x){
    int len = x.size() - 1;poly res(len);
    for(int i = 0;i < len; ++i) res[i] = 1ll*x[i+1]*(i+1)%_P;
    return res;
  }
  IL poly Int(poly x){
    int len = x.size() + 1;poly res(len);
    for(int i = 1;i < len; ++i) res[i] = 1ll*x[i-1]*invn[i]%_P;
    return res;
  }
  poly ln(poly x,int n){
    poly res = Int(invp(x,n)*Diff(x));
    res.resize(n);return res;
  }
  poly exp(poly x,int n){
    if(n == 1) return {1};
    poly y = exp(poly(x.begin(),x.begin()+((n+1)>>1)),(n+1)>>1);
    poly res = y*(poly{1}-ln(y,n)+x);
    res.resize(n);
    return res;
  }
  IL int BSGS(int a,int p,int n){
    unordered_map<int,int> mp;
  	int m = ceil(sqrt(p)),tmp = 1;
  	for(int i=0;i<m;i++) mp[1ll*tmp*n%p] = i+1,tmp = 1ll*tmp*a%p;
  	int tmpp = 1;
  	for(int i=0;i<=m;i++){
  		if(mp[tmpp]) return (1ll*i*m%p-mp[tmpp]+1+p)%p;
  		tmpp=1ll*tmpp*tmp%p;
  	}
  	return -1;
  }
  poly sqrtp(poly x,int n){
    if(n == 1){
      int p = BSGS(3,_P,x[0]);
      p = qpow(3,p/2);
      return {min(p,_P-p)};
    }
    //x.resize(n);
    poly y = sqrtp(poly(x.begin(),x.begin()+(n+1)/2),(n+1)/2);
    poly res = (y+x*invp(y,n))*poly({(_P+1)/2});res.resize(n);
    return res;
  }
  poly Pow(poly x,int k){
    int n = x.size();
    x = ln(x,n);
    for(int i = 0;i < n; ++i) x[i] = 1ll*x[i]*k%_P;
    return exp(x,n);
  }
  poly Pow(poly x,int k,int n){
    x = ln(x,n);
    for(int i = 0;i < n; ++i) x[i] = 1ll*x[i]*k%_P;
    x = exp(x,n);
    return x;
  }
  int _get(string s,int Mod = _P - 1){
    int res = 0;
    for(int i = 0;i < s.size(); ++i)
      res = (res*10ll + s[i]-48)%Mod;
    return res;
  }
  poly powp(poly x,string k){
    int n = x.size(),pp = -1;
    for(int i = 0;i < n; ++i) if(x[i]) {pp = i;break;}
    for(int i = 0;i < n-pp; ++i) x[i] = x[i+pp];
    int a = x[0],ia = invi(a);
    for(auto &i:x) i = 1ll*i*ia%_P;
    a = qpow(a,_get(k));
    if(k.size() <= 9){
      int p = 0;
      for(char c:k) p = p*10+c-48;
      if(1ll*pp*p < n){
        x.resize(n-pp*p);
        x = Pow(x,p,n-pp*p);
        poly res(n);
        for(int i = 0;i < n-pp*p; ++i) res[i+pp*p] = 1ll*x[i]*a%_P;
        return res;
      }
      else return poly(n);
    }
    if(pp) return poly(n);
    x = ln(x,n) * poly{_get(k,_P)};
    x = exp(x,n)*(poly){a};
    x.resize(n);
    return x;
  }
#undef IL
}using namespace PolyBasedNTT;
const int N = 1e5 + 10,Mx = 1e5,Mod = 998244353;
int n,m,k,a[N],b[N],fac[N],inv[N];
poly G(int *a,int n){
	auto Get = [&](int l,int r,auto &&slf) -> poly{
		if(l == r) return (poly){1,Mod-a[l]};
		int mid = (l + r) >> 1;
		return slf(l,mid,slf)*slf(mid+1,r,slf);
	};
	auto f = Get(1,n,Get);
	f.resize(k+1);
	f = ln(f,f.size());
	f = Diff(f);
	f = (poly){0,Mod-1}*f+(poly){n};
	Diff(f);
	return f;
}
signed main(){
  cin.tie(nullptr)->sync_with_stdio(false);
	fac[0] = 1;for(int i = 1;i <= Mx; ++i) fac[i] = 1ll*fac[i-1]*i%Mod;
	inv[Mx] = qpow(fac[Mx],Mod-2,Mod);
	for(int i = Mx - 1;i >= 0; --i) inv[i] = 1ll*inv[i+1]*(i+1)%Mod;
	Poly_pre();_invpre();
	cin>>n>>m;
	for(int i = 1;i <= n; ++i) cin>>a[i];
	for(int i = 1;i <= m; ++i) cin>>b[i];
	cin>>k;
	auto f = G(a,n);
	auto g = G(b,m);
	for(int i = 0;i < f.size(); ++i) f[i] = 1ll*f[i]*inv[i]%Mod;
	for(int i = 0;i < g.size(); ++i) g[i] = 1ll*g[i]*inv[i]%Mod;
	f = f*g;
	int inm = qpow(1ll*n*m%Mod,Mod-2,Mod);
	for(int i = 1;i <= k; ++i){
		cout<<1ll*f[i]*fac[i]%Mod*inm%Mod<<'\n';
	}
}
因为不是鲜花,所以就不放图了

算了还是放把。
image

posted @ 2025-02-17 21:02  CuFeO4  阅读(28)  评论(1)    收藏  举报