【CTS2019Day1】珍珠

传送门.


不知道怎么说这题,考场时完全没有想过生成函数,随便想想就有70+分了啊。

考虑d个中如果有k个是奇数,则 ( n − k ) / 2 > = m (n-k)/2>=m (nk)/2>=m
k &lt; = n − 2 m k&lt;=n-2m k<=n2m,当然 k &lt; = D k&lt;=D k<=D

f [ k ] f[k] f[k]表示k个奇数的方案。

考虑用生成函数强解:
f [ k ] = C D k ∗ D ! ∗ ( e x − e − x 2 ) k ∗ ( e x + e − x 2 ) D − k [ x n ] f[k]=C_{D}^k*D!*({e^x-e^{-x}\over2})^k*({e^x+e^{-x}\over2})^{D-k}[x^n] f[k]=CDkD!(2exex)k(2ex+ex)Dk[xn]
发现这个真的不会拆了,但是随便写写就有70分了。

不好拆的关键主要在于有两个东西,不妨容斥一下

g [ k ] g[k] g[k]表示至少k个的方案
g [ k ] = ∑ i = k D C i k ∗ f [ i ] g[k]=\sum_{i=k}^DC_{i}^k*f[i] g[k]=i=kDCikf[i]
f [ k ] = ∑ i = k D C i k ∗ g [ i ] ∗ ( − 1 ) i − k f[k]=\sum_{i=k}^DC_{i}^k*g[i]*(-1)^{i-k} f[k]=i=kDCikg[i](1)ik

g [ k ] = C D k ∗ D ! ∗ e D − k ∗ ( e x − e − x 2 ) k [ x n ] g[k]=C_{D}^k*D!*e^{D-k}*({e^x-e^{-x}\over2})^k[x^n] g[k]=CDkD!eDk(2exex)k[xn]
g [ k ] = C D k ∗ D ! ∗ 2 − k ∗ e ( D − k ) x ∗ ∑ i = 0 k ( − 1 ) i ∗ e i x + ( k − i ) x [ x n ] ∗ C k i g[k]=C_{D}^k*D!*2^{-k}*e^{(D-k)x}*\sum_{i=0}^k(-1)^i*e^{ix+(k-i)x}[x^n]*C_{k}^i g[k]=CDkD!2ke(Dk)xi=0k(1)ieix+(ki)x[xn]Cki
g [ k ] = C D k ∗ D ! ∗ 2 − k ∗ ∑ i = 0 k ( − 1 ) i ∗ e i x + ( k − i ) x + ( D − k ) x [ x n ] ∗ C k i g[k]=C_{D}^k*D!*2^{-k}*\sum_{i=0}^k(-1)^i*e^{ix+(k-i)x+(D-k)x}[x^n]*C_{k}^i g[k]=CDkD!2ki=0k(1)ieix+(ki)x+(Dk)x[xn]Cki
g [ k ] = C D k ∗ D ! ∗ 2 − k ∗ ∑ i = 0 k ( − 1 ) i ∗ e ( D − 2 i ) x [ x n ] ∗ C k i g[k]=C_{D}^k*D!*2^{-k}*\sum_{i=0}^k(-1)^i*e^{(D-2i)x}[x^n]*C_{k}^i g[k]=CDkD!2ki=0k(1)ie(D2i)x[xn]Cki
g [ k ] = C D k ∗ D ! ∗ 2 − k ∗ ∑ i = 0 k ( − 1 ) i ∗ ( D − 2 i ) n ∗ C k i g[k]=C_{D}^k*D!*2^{-k}*\sum_{i=0}^k(-1)^i*(D-2i)^n*C_{k}^i g[k]=CDkD!2ki=0k(1)i(D2i)nCki

到这一步已经非常显然的可以 N T T NTT NTT优化了。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i <  B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
#define ui unsigned int
using namespace std;

const int mo = 998244353;

ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

const int N = 1e5 + 4;

ll a[N * 4], b[N * 4]; int r[N * 4];
void dft(ll *a, int n, int f) {
	ff(i, 0, n) {
		r[i] = r[i / 2] / 2 + (i & 1) * n / 2;
		if(i < r[i]) swap(a[i], a[r[i]]);
	}
	for(int h = 1; h < n; h *= 2) {
		ll wn = ksm(ksm(3, (mo - 1) / 2 / h), f == 1 ? 1 : mo - 2);
		for(int j = 0; j < n; j += 2 * h) {
			ll w = 1, b, *l = a + j, *r = a + j + h;
			ff(i, 0, h) {
				b = *r * w, *r = (*l - b) % mo, *l = (*l + b) % mo;
				w = w * wn % mo, l ++, r ++;
			}
		}
	}
	if(f == -1) {
		ll v = ksm(n, mo - 2);
		ff(i, 0, n) a[i] = (a[i] + mo) * v % mo;
	}
}
void fft(ll *a, ll *b, int n) {
	dft(a, n, 1); dft(b, n, 1);
	ff(i, 0, n) a[i] = a[i] * b[i] % mo;
	dft(a, n, -1);
}

int n, n2, m;
ll fac[N], nf[N];

#define mem(a) memset(a, 0, sizeof a)

int main() {
	scanf("%d %d %d", &n, &n2, &m);
	fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
	nf[n] = ksm(fac[n], mo - 2); fd(i, n, 1) nf[i - 1] = nf[i] * i % mo;
	int tp = 0; while(1 << ++ tp <= 2 * n);
	fo(i, 0, n) {
		a[i] = ksm(n - 2 * i, n2) * (i % 2 ? -1 : 1) * nf[i] % mo;
		b[i] = nf[i];
	}
	fft(a, b, 1 << tp);
	ff(i, n + 1, 1 << tp) a[i] = 0;
	mem(b);
	fo(i, 0, n) {
		a[i] = a[i] * ksm((mo + 1) / 2, i) % mo * fac[n] % mo * nf[n - i] % mo * fac[i] % mo;
		b[n - i] = nf[i] % mo * (i % 2 ? -1 : 1);
	}
	fft(a, b, 1 << tp);
	fo(i, 0, n) a[i] = a[i + n] * nf[i] % mo;
	ll ans = 0;
	fo(i, 0, min(n2 - 2 * m, n)) ans += a[i];
	pp("%lld\n", (ans % mo + mo) % mo);
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值