题解 数论 / [牛客11259H] Scholomance Academy

传送门
[牛客11259H] Scholomance Academy

先考虑 \(t=1\) 的情况
此时 \(a_1a_2\cdots a_m=n\) 的限制可以变为对 \(\sum\) 的限制
考虑用 \(\varphi(p^k)\) 关于 \(k\) 的生成函数来处理这个加法卷积
\([x^k]F_p(x)=\varphi(p^k)\)
那么

\[F_p(x)=1+(p-1)x+(p-1)px^2+\cdots \]

寻找其封闭形式

\[\frac{p}{p-1}F_p(x)=\frac{p}{p-1}+px+p^2x^2+\cdots \]

\(t=\frac{p}{p-1}(F_p(x)-1)\),则 \(t\) 是公比为 \(px\) 的等比数列
求和后得

\[F_p(x)=\frac{1-x}{1-px} \]

那么就要求

\[[x^n](\frac{1-x}{1-px})^m \]

引入求分式远项的新科技 Bostan-Mori 算法:

\[[x^n]\frac{F(x)}{G(x)} \]

考虑

\[[x^n]\frac{F(x)G(-x)}{G(x)G(-x)} \]

发现分母仅偶数次项有值
那么其逆也仅偶数次项有值
关于逆那部分的证明不会
也许可以用 一定存在仅偶数次项有值的逆 和 逆是唯一的 得到?
继续发现一个多项式乘仅偶数次项有值的多项式,其奇偶次项互不干扰
即可以写成

\[F(x)G(x)=P(x^2)+xQ(x^2) \]

那么只需要根据 \(n\) 的奇偶性判断应递归处理 \(P\) 还是 \(Q\) 即可
换元为 \(x'=x^2\) 后多项式长度不变
递归到 \(n=0\) 时答案即为 \(\frac{[x^0]F(x)}{[x^0]G(x)}\)

然后回到本题,处理 \(t>1\) 的情况
发现不同的 \(p\) 之间是完全独立的,可以直接乘起来

\[\frac{(1-x)^{tm}}{\prod\limits_{i=1}^t(1-p_ix)^m} \]

上面可以直接二项式定理展开
下面可以分治+NTT 做到 \(O(tm\log{tm})\)
然后 Bostan-Mori 即可
复杂度 \(O(tm\log^2{tm})\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2000010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, t, m;
int p[N], rev[N];
const ll mod=998244353, rt=3, phi=mod-1;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

namespace task1{
	int a[N];
	ll pw[N], ans;
	void dfs(int u, int rest) {
		if (u>m) {
			if (rest) return ;
			ll tem=1;
			for (int i=1; i<=m; ++i) if (a[i])
				tem=tem*(p[1]-1)%mod*pw[a[i]-1]%mod;
			ans=(ans+tem)%mod;
			return ;
		}
		for (int i=0; i<=rest; ++i) a[u]=i, dfs(u+1, rest-i);
	}
	void solve() {
		pw[0]=1;
		for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*p[1]%mod;
		dfs(1, n);
		printf("%lld\n", ans);
	}
}

namespace task2{
	ll ans;
	void solve() {
		for (int i=1; i<=t; ++i) ans=(ans+1ll*(p[i]-1)*m)%mod;
		printf("%lld\n", ans);
	}
}

namespace task{
	ll fac[N], inv[N];
	inline ll C(int n, int k) {return fac[n]*inv[k]%mod*inv[n-k]%mod;}
	struct poly{
		vector<ll> a;
		inline int len() {return a.size();}
		inline void resize(int t) {a.resize(t);}
		inline ll& operator [] (int t) {return a[t];}
		inline void clr(int len) {for (int i=0; i<len; ++i) a[i]=0;}
		inline void cpy(poly& a, poly& b, int len) {for (int i=0; i<len; ++i) a[i]=b[i];}
		inline void mul(poly& a, poly& b, int len) {for (int i=0; i<len; ++i) a[i]=a[i]*b[i]%mod;}
		inline void adjust() {while (a.size()&&!a.back()) a.pop_back();}
		void ntt(int len, int op) {
			int bct=ceil(log2(len));
			for (int i=0; i<len; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bct-1));
			for (int i=0; i<len; ++i) if (i<rev[i]) swap(a[i], a[rev[i]]);
			ll w, wn, t;
			for (int i=1; i<len; i<<=1) {
				wn=qpow(rt, (op*phi/(i<<1)+phi)%phi);
				for (int j=0,step=i<<1; j<len; j+=step) {
					w=1;
					for (int k=j; k<j+i; ++k,w=w*wn%mod) {
						t=a[k+i]*w%mod;
						a[k+i]=(a[k]-t)%mod;
						a[k]=(a[k]+t)%mod;
					}
				}
			}
			if (op==-1) {
				ll inv=qpow(len, mod-2);
				for (int i=0; i<len; ++i) a[i]=a[i]*inv%mod;
			}
		}
		poly operator * (poly b) {
			poly t1=*this, t2=b;
			int len, n=t1.len()+t2.len()-1;
			for (len=1; len<=n; len<<=1) ;
			t1.resize(len); t2.resize(len);
			t1.ntt(len, 1); t2.ntt(len, 1);
			mul(t1, t2, len);
			t1.ntt(len, -1);
			t1.adjust();
			return t1;
		}
	}f, g;
	poly solve(int l, int r) {
		if (l==r) {
			poly ans; ans.resize(m+1);
			for (ll i=0,now=1; i<=m; ++i,now=now*(-p[l])%mod)
				ans[i]=C(m, i)*now%mod;
			return ans;
		}
		int mid=(l+r)>>1;
		return solve(l, mid)*solve(mid+1, r);
	}
	ll mori(int n, poly f, poly g) {
		for (int i; n; n>>=1) {
			poly t=g;
			for (i=1; i<t.len(); i+=2) t[i]=-t[i];
			f=f*t; g=g*t;
			for (i=n&1; i<f.len(); i+=2) f[i>>1]=f[i];
			f.resize(i>>1);
			for (i=0; i<g.len(); i+=2) g[i>>1]=g[i];
			g.resize(i>>1);
		}
		return f.len()?f[0]*qpow(g[0], mod-2)%mod:0;
	}
	void solve() {
		fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		for (int i=2; i<=t*m; ++i) fac[i]=fac[i-1]*i%mod;
		for (int i=2; i<=t*m; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=2; i<=t*m; ++i) inv[i]=inv[i-1]*inv[i]%mod;
		f.resize(t*m+1);
		for (int i=0; i<=t*m; ++i) f[i]=C(t*m, i)*(i&1?-1:1)%mod;
		g=solve(1, t);
		printf("%lld\n", (mori(n, f, g)%mod+mod)%mod);
	}
}

signed main()
{
	freopen("math.in", "r", stdin);
	freopen("math.out", "w", stdout);

	n=read(); t=read(); m=read();
	for (int i=1; i<=t; ++i) p[i]=read();
	// if (t==1) task1::solve();
	// else if (n==1) task2::solve();
	// else puts("0");
	task::solve();

	return 0;
}
posted @ 2022-07-08 07:20  Administrator-09  阅读(9)  评论(0编辑  收藏  举报