BZOJ 2655: calc

考虑升序序列对答案的贡献,最后只需要乘上 \(n!\) 即可
\(f_{i,j}\) 表示已经放了 \(i\) 个数,且最大值不超过 \(j\) 的方案数
\(f_{i,j}=j \times f_{i-1,j-1}+f_{i,j-1}\)
那么答案为 \(f_{n,A}\)
不难 发现 \(f_{n,i}\) 是关于 \(i\)\(2n+1\) 阶多项式
\(g_{i,j}\) 表示已经放了 \(i\) 个数,且最大值恰好为 \(j\) 的方案数
\(g_{i,j}=j \times \sum\limits_{k=0}^{j-1}g_{i-1,k}\)
那么 \(f_{n,A}=\sum\limits_{i=0}^A g_{n,i}\)
每次 \(g\) 都进行一次前缀和以及乘上 \(j\),那么每次次数都会加 \(2\)
最后再对 \(g\) 求一次前缀和
所以次数是 \(2n+1\)
直接拉格朗日插值就行了

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<ll, int>
#define SZ(x) ((int)(x).size())
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) / 2)
#define lowbit(i) ((i) & (-i))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=((b)-1);i>=(a);i--)
#define Edg int ccnt=1,head[N],to[E],ne[E];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[E],ne[E],c[E];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
int MOD;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2, int mod = MOD) {int ans = 1; for (; b; a = 1LL * a * a % mod, b >>= 1)if (b & 1)ans = 1LL * ans * a % mod; return ans % mod;}
template<class T>T gcd(T a, T b) { while (b) { a %= b; std::swap(a, b); } return a; }
template<class T>bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<class T>bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
	return x * f;
}

const int N = 1234;

namespace XX {
	int lagrange(int n, int *x, int *y, int k) {
		int ans = 0;
		rep (i, 1, n + 1) {
			int fz = 1, fm = 1;
			rep (j, 1, n + 1) if (i != j) {
				fz = 1ll * fz * (k - x[j] + MOD) % MOD;
				fm = 1ll * fm * (x[i] - x[j] + MOD) % MOD;
			}
			M(ans += 1ll * y[i] * fz % MOD * qp(fm) % MOD);
		}
		return ans;
	}
	int pre[N], suf[N], fac_inv[N], inv[N];
	void init() {
		inv[1] = fac_inv[0] = fac_inv[1] = 1;
		rep (i, 2, N) {
			inv[i] = 1ll * (MOD - MOD / i) * inv[MOD % i] % MOD;
			fac_inv[i] = 1ll * fac_inv[i - 1] * inv[i] % MOD;
		}
	}
	int lagrange(int n, int *y, int k) {
		int ans = 0;
		pre[0] = suf[n + 1] = 1;
		rep (i, 1, n + 1) pre[i] = 1ll * pre[i - 1] * (k - i) % MOD;
		per (i, 1, n + 1) suf[i] = 1ll * suf[i + 1] * (k - i) % MOD;
		rep (i, 1, n + 1) {
			int cur = 1ll * pre[i - 1] * suf[i + 1] % MOD * fac_inv[i - 1] % MOD * fac_inv[n - i] % MOD;
			if ((n - i) & 1) cur = MOD - cur;
			M(ans += 1ll * cur * y[i] % MOD);
		}
		return ans;
	}
}

int f[N][N], A, n;

int main() {
#ifdef LOCAL
	freopen("ans.out", "w", stdout);
#endif
	
	A = _(), n = _(), MOD = _();
	int m = 2 * n + 1;
	rep (i, 0, m + 1) f[0][i] = 1;
	rep (i, 1, n + 1) {
		rep (j, 1, m + 1) {
			M(f[i][j] = 1ll * j * f[i - 1][j - 1] % MOD + f[i][j - 1]);
		}
	}
	XX::init();
	int ans = 1;
	rep (i, 1, n + 1) ans = 1ll * ans * i % MOD;
	ans = 1ll * ans * XX::lagrange(m, f[n], A) % MOD;
	printf("%d\n", ans);

#ifdef LOCAL
	printf("%.10f\n", (db)clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}
posted @ 2020-03-17 16:11  Mrzdtz220  阅读(110)  评论(0编辑  收藏  举报