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 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';
}
}
因为不是鲜花,所以就不放图了
算了还是放把。
__________________________________________________________________________________________
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18720818