牛客练习赛32 F-Friendly Polynomial NTT+多项式求逆+组合计数
传送门: https://ac.nowcoder.com/acm/contest/272/F
题意
给
一
个
n
,
表
示
有
1
到
n
这
些
数
,
对
于
一
个
i
,
如
果
前
i
个
是
1
到
i
的
一
个
排
列
,
则
整
个
序
列
称
为
不
合
格
序
列
。
给一个n,表示有1到n这些数,对于一个i,如果前i个是1到i的一个排列,则整个序列称为不合格序列。
给一个n,表示有1到n这些数,对于一个i,如果前i个是1到i的一个排列,则整个序列称为不合格序列。
求
出
所
有
不
合
格
序
列
个
数
。
求出所有不合格序列个数。
求出所有不合格序列个数。
思路
考 虑 把 序 列 以 i 为 界 限 拆 成 两 半 , 设 f n 为 长 度 为 n 的 不 合 格 序 列 个 数 , 则 : 考虑把序列以i为界限拆成两半,设f_n为长度为n 的不合格序列个数,则: 考虑把序列以i为界限拆成两半,设fn为长度为n的不合格序列个数,则:
- 前 i 个 是 不 合 格 序 列 , 贡 献 为 i ! 。 前i个是不合格序列,贡献为i!。 前i个是不合格序列,贡献为i!。
- 后 n − i 个 不 是 不 合 格 序 列 , 贡 献 为 ( n − i ) ! − f n − i 后n-i个不是不合格序列,贡献为(n-i)!-f_{n-i} 后n−i个不是不合格序列,贡献为(n−i)!−fn−i
则
对
于
任
意
一
个
n
来
说
,
则对于任意一个n来说,
则对于任意一个n来说,
f
n
=
∑
i
=
1
n
−
1
i
!
∗
[
(
n
−
i
)
!
−
f
n
−
i
]
f_n=\sum_{i=1}^{n-1}i!*[(n-i)!-f_{n-i}]
fn=i=1∑n−1i!∗[(n−i)!−fn−i]
f n = ∑ i = 1 n − 1 i ! ∗ ( n − i ) ! − ∑ i = 1 n − 1 i ! ∗ f n − i f_n=\sum_{i=1}^{n-1}i!*(n-i)!-\sum_{i=1}^{n-1}i!*f_{n-i} fn=i=1∑n−1i!∗(n−i)!−i=1∑n−1i!∗fn−i
设 g n = n ! , 特 别 的 , g 0 = 0 ! = 0 , 则 : 设\red{g_n=n!,特别的,g_0=0!=0,则:} 设gn=n!,特别的,g0=0!=0,则:
f = g ∗ g − g ∗ f f=g*g-g*f f=g∗g−g∗f
f = g ∗ g 1 + g f=\frac{g*g}{1+g} f=1+gg∗g
需 要 一 个 多 项 式 求 逆 , 多 项 式 乘 法 , 直 接 套 即 可 。 需要一个多项式求逆,多项式乘法,直接套即可。 需要一个多项式求逆,多项式乘法,直接套即可。
因 为 我 的 板 子 都 是 任 意 模 数 M T T , 所 以 直 接 省 略 N T T 了 , 全 是 M T T 。 因为我的板子都是任意模数MTT,所以直接省略NTT了,全是MTT。 因为我的板子都是任意模数MTT,所以直接省略NTT了,全是MTT。
Code(1579MS)
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
#define endl "\n"
const ll mod = 998244353;
const double PI = acos(-1);
const int N = 1e6 + 10;
struct Complex {
double x, y;
Complex(double a = 0, double b = 0): x(a), y(b) {}
Complex operator + (const Complex &rhs) { return Complex(x + rhs.x, y + rhs.y); }
Complex operator - (const Complex &rhs) { return Complex(x - rhs.x, y - rhs.y); }
Complex operator * (const Complex &rhs) { return Complex(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x); }
Complex conj() { return Complex(x, -y); }
} w[N];
int tr[N];
ll f[N], g[N], invg[N], g2[N];
ll quick_pow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans % mod;
}
int getLen(int n) {
int len = 1; while (len < (n << 1)) len <<= 1;
for (int i = 0; i < len; i++) tr[i] = (tr[i >> 1] >> 1) | (i & 1 ? len >> 1 : 0);
for (int i = 0; i < len; i++) w[i] = w[i] = Complex(cos(2 * PI * i / len), sin(2 * PI * i / len));
return len;
}
void FFT(Complex *A, int len) {
for (int i = 0; i < len; i++) if(i < tr[i]) swap(A[i], A[tr[i]]);
for (int i = 2, lyc = len >> 1; i <= len; i <<= 1, lyc >>= 1)
for (int j = 0; j < len; j += i) {
Complex *l = A + j, *r = A + j + (i >> 1), *p = w;
for (int k = 0; k < i >> 1; k++) {
Complex tmp = *r * *p;
*r = *l - tmp, *l = *l + tmp;
++l, ++r, p += lyc;
}
}
}
inline void MTT(ll *x, ll *y, ll *z, int n) {
int len = 1; while (len <= n) len <<= 1;
for (int i = 0; i < len; i++) tr[i] = (tr[i >> 1] >> 1) | (i & 1 ? len >> 1 : 0);
for (int i = 0; i < len; i++) w[i] = w[i] = Complex(cos(2 * PI * i / len), sin(2 * PI * i / len));
for (int i = 0; i < len; i++) (x[i] += mod) %= mod, (y[i] += mod) %= mod;
static Complex a[N], b[N];
static Complex dfta[N], dftb[N], dftc[N], dftd[N];
for (int i = 0; i < len; i++) a[i] = Complex(x[i] & 32767, x[i] >> 15);
for (int i = 0; i < len; i++) b[i] = Complex(y[i] & 32767, y[i] >> 15);
FFT(a, len), FFT(b, len);
for (int i = 0; i < len; i++) {
int j = (len - i) & (len - 1);
static Complex da, db, dc, dd;
da = (a[i] + a[j].conj()) * Complex(0.5, 0);
db = (a[i] - a[j].conj()) * Complex(0, -0.5);
dc = (b[i] + b[j].conj()) * Complex(0.5, 0);
dd = (b[i] - b[j].conj()) * Complex(0, -0.5);
dfta[j] = da * dc;
dftb[j] = da * dd;
dftc[j] = db * dc;
dftd[j] = db * dd;
}
for (int i = 0; i < len; i++) a[i] = dfta[i] + dftb[i] * Complex(0, 1);
for (int i = 0; i < len; i++) b[i] = dftc[i] + dftd[i] * Complex(0, 1);
FFT(a, len), FFT(b, len);
for (int i = 0; i < len; i++) {
int da = (ll)(a[i].x / len + 0.5) % mod;
int db = (ll)(a[i].y / len + 0.5) % mod;
int dc = (ll)(b[i].x / len + 0.5) % mod;
int dd = (ll)(b[i].y / len + 0.5) % mod;
z[i] = (da + ((ll)(db + dc) << 15) + ((ll)dd << 30)) % mod;
}
}
void Get_Inv(ll *f, ll *g, int n) {
if(n == 1) { g[0] = quick_pow(f[0], mod - 2); return ; }
Get_Inv(f, g, (n + 1) >> 1);
int len = getLen(n);
static ll c[N];
for(int i = 0;i < len; i++) c[i] = i < n ? f[i] : 0;
MTT(c, g, c, len); MTT(c, g, c, len);
for(int i = 0;i < n; i++) g[i] = (2ll * g[i] - c[i] + mod) % mod;
for(int i = n;i < len; i++) g[i] = 0;
for(int i = 0;i < len; i++) c[i] = 0;
}
void init() {
g[0] = 1; for(int i = 1;i < 1e5 + 10; i++) g2[i] = g[i] = g[i - 1] * i % mod;
Get_Inv(g, invg, 1e5);
g[0] = g2[0] = 0;
MTT(g2, g, g2, 1e5 + 1e5);
MTT(g2, invg, f, 2e5 + 1e5);
}
void solve() {
init();
int _; cin >> _;
while(_--) {
int n; cin >> n;
cout << f[n] << endl;
}
}
signed main() {(cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
}