[HEOI2016/TJOI2016]求和 NTT

题目链接

HEOI2016/TJOI2016求和

题目大意


f ( n ) = ∑ i = 0 n ∑ j = 0 n S ( i , j ) 2 j ( j ! ) f(n)=\sum_{i=0}^n\sum_{j=0}^nS(i,j)2^j(j!) f(n)=i=0nj=0nS(i,j)2j(j!)

推式子

f ( n ) = ∑ i = 0 n ∑ j = 0 i S ( i , j ) 2 j ( j ! ) = ∑ i = 0 n ∑ j = 0 n S ( i , j ) 2 j ( j ! ) = ∑ j = 0 n 2 j ( j ! ) ∑ i = 0 n S ( i , j ) = ∑ j = 0 n 2 j ( j ! ) ∑ i = 0 n ∑ k = 0 j ( − 1 ) k 1 k ! ( j − k ) ! ( j − k ) i = ∑ j = 0 n 2 j ( j ! ) ∑ k = 0 j ( − 1 ) k 1 k ! ( j − k ) ! ∑ i = 0 n ( j − k ) i = ∑ j = 0 n 2 j ( j ! ) ∑ k = 0 j ( − 1 ) k k ! ∑ i = 0 n ( j − k ) i ( j − k ) ! \begin{aligned}f(n)&=\sum_{i=0}^{n}\sum_{j=0}^iS(i,j)2^j(j!)\\&=\sum_{i=0}^{n}\sum_{j=0}^nS(i,j)2^j(j!)\\&=\sum_{j=0}^{n}2^j(j!)\sum_{i=0}^nS(i,j)\\&=\sum_{j=0}^{n}2^j(j!)\sum_{i=0}^n\sum_{k=0}^j(-1)^k\frac{1}{k!(j-k)!}(j-k)^i\\&=\sum_{j=0}^{n}2^j(j!)\sum_{k=0}^j(-1)^k\frac{1}{k!(j-k)!}\sum_{i=0}^n(j-k)^i\\&=\sum_{j=0}^{n}2^j(j!)\sum_{k=0}^j\frac{(-1)^k}{k!}\frac{\sum_{i=0}^n(j-k)^i}{(j-k)!}\end{aligned} f(n)=i=0nj=0iS(i,j)2j(j!)=i=0nj=0nS(i,j)2j(j!)=j=0n2j(j!)i=0nS(i,j)=j=0n2j(j!)i=0nk=0j(1)kk!(jk)!1(jk)i=j=0n2j(j!)k=0j(1)kk!(jk)!1i=0n(jk)i=j=0n2j(j!)k=0jk!(1)k(jk)!i=0n(jk)i

g ( n ) = ∑ k = 0 j ( − 1 ) k k ! ∑ i = 0 n ( j − k ) i ( j − k ) ! g(n)=\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{\sum_{i=0}^n(j-k)^i}{(j-k)!} g(n)=k=0jk!(1)k(jk)!i=0n(jk)i,发现这个式子可以卷积。

a i = ( − 1 ) i i ! , b i = ∑ k = 0 n i k i ! = i n + 1 − 1 ( i − 1 ) i ! a_i=\frac{(-1)^i}{i!},b_i=\frac{\sum_{k=0}^ni^k}{i!}=\frac{i^{n+1}-1}{(i-1)i!} ai=i!(1)i,bi=i!k=0nik=(i1)i!in+11,那么 g ( n ) = ∑ i = 0 n a i b n − i g(n)=\sum_{i=0}^na_ib_{n-i} g(n)=i=0naibni。所以 f ( n ) = ∑ i = 0 n 2 i ( i ! ) g ( i ) 。 f(n)=\sum_{i=0}^n2^i(i!)g(i)。 f(n)=i=0n2i(i!)g(i)

时间复杂度 O(nlogn) \text{O(nlogn)} O(nlogn)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 5, mod = 998244353, G = 3, Gi = 332748118;
int n, lim = 1, L, r[N]; ll ans, fac[N], inv[N], a[N], b[N], g[N];
inline ll qpow(ll a, ll b) { ll ans = 1; for (; b ; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod; return ans; }
inline void get(int n = N - 1) {
	fac[0] = 1; for (int i = 1; i <= n; ++ i) fac[i] = fac[i - 1] * i % mod;
	inv[n] = qpow(fac[n], mod - 2); for (int i = n - 1; i >= 0; -- i) inv[i] = (i + 1) * inv[i + 1] % mod;
}
inline void NTT(ll *A, int type) {
	for (int i = 0; i < lim; ++ i) if (i < r[i]) swap(A[i], A[r[i]]);
	for (int mid = 1; mid < lim; mid <<= 1) {
		ll Wn = qpow(type == 1 ? G : Gi, (mod - 1) / (mid << 1));
		for (int j = 0; j < lim; j += (mid << 1)) {
			ll w = 1;
			for (int k = 0; k < mid; ++ k, w = w * Wn % mod) {
				int x = A[j + k], y = w * A[j + k + mid] % mod;
				A[j + k] = (x + y) % mod, A[j + k + mid] = (x - y + mod) % mod;
			}
		}
	}
}
int main() {
	scanf("%d", &n), get(n);
	for (int i = 0; i <= n; ++ i) a[i] = qpow(mod - 1, i) * qpow(fac[i], mod - 2) % mod;
	b[0] = 1, b[1] = n + 1; for (int i = 2; i <= n; ++ i) b[i] = (qpow(i, n + 1) - 1 + mod) % mod * qpow(i - 1, mod - 2) % mod * qpow(fac[i], mod - 2) % mod;
	while (lim <= n + n) lim <<= 1, ++ L;
	for (int i = 0; i < lim; ++ i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
	NTT(a, 1), NTT(b, 1);
	for (int i = 0; i < lim; ++ i) a[i] = a[i] * b[i] % mod;
	NTT(a, -1);
	ll inv = qpow(lim, mod - 2), x = 1;
	for (int i = 0; i <= n; ++ i) g[i] = a[i] * inv % mod;
	for (int i = 0; i <= n; ++ i, x = (x << 1) % mod) (ans += x * fac[i] % mod * g[i] % mod) %= mod; 
	return printf("%lld\n", ans), 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值