P5259 [JSOI2013]游戏中的学问

环排列的EGF为:

\[f(x)=\sum_{3\le i} {(i-1)! x^i \over i!}=\sum_{3\le i} {x^i \over i} \]

那么这道题答案就是 :

\[{n!\over k!}[x^n]f^k(x) \]

数据范围太小,甚至多项式乘法不用 NTT

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 3005;

int n, k, p;

inline int power(int a, int b) {
	int k = b, t = 1, y = a;
	while (k) {
		if (k & 1) t = (1ll * t * y) % p;
		y = (1ll * y * y) % p; k >>= 1;
	} return t;
}

inline int inv(int x)  {
	return power(x, p - 2);
}

int t[N], y[N], a[N], ans = 1;

int main() {
	scanf("%d%d%d", &n, &k, &p);
	for (int i = k + 1; i <= n; ++i) ans = (1ll * ans * i) % p;
	memset(t, 0, sizeof t); t[0] = 1;
	for (int i = 3; i <= n; ++i) y[i] = inv(i);
	while (k) {
		if (k & 1) {
			for (int i = 0; i <= n; ++i) a[i] = t[i];
			memset(t, 0, sizeof t);
			for (int i = 0; i <= n; ++i)
				for (int j = 0; j + i <= n; ++j) {
					t[i + j] += 1ll * a[i] * y[j] % p;
					if (t[i + j] >= p) t[i + j] -= p;
				}
		} k >>= 1;
		for (int i = 0; i <= n; ++i) a[i] = y[i];
		memset(y, 0, sizeof y);
		for (int i = 0; i <= n; ++i)
			for (int j = 0; j + i <= n; ++j) {
				y[i + j] += 1ll * a[i] * a[j] % p;
				if (y[i + j] >= p) y[i + j] -= p;
			}
	} printf("%d", ((1ll * ans * t[n]) % p + p) % p);
	return 0;
}
上一篇:2021-2022学年英语周报九年级第24期答案及试题


下一篇:SQL server使用ROW_NUMBER() OVER()做过滤