省选联考 2020 A 卷

省赛虽然炸了,但题解还是要写滴(笑)

第 200 篇 b l o g 祭 ! ! \Huge 第200篇blog祭!! 200blog!

组合数问题

题意简单明了

首先要看出要把多项式的每一项分别算

c c c项的答案就是
a c ∗ ∑ k = 0 n k c × x k × C n k \large a_c*\sum\limits_{k=0}^n k^c \times x^k \times C_{n}^{k} ack=0nkc×xk×Cnk
先把 a c a_c ac扔了,看后面的那个式子,发现 c c c比较小
考虑第二类斯特林数 n m = ∑ i = 0 m S ( m , i ) × n ! ( n − i ) ! n^m=\sum\limits_{i=0}^m S(m,i) \times \frac{n!}{(n - i)!} nm=i=0mS(m,i)×(ni)!n!
带入上式
∑ k = 0 n ∑ i = 0 c S ( c , i ) × k ! ( k − i ) ! × x k × C n k \large \sum\limits_{k=0}^n \sum\limits_{i=0}^c S(c,i) \times \frac{k!}{(k - i)!} \times x^k \times C_{n}^{k} k=0ni=0cS(c,i)×(ki)!k!×xk×Cnk
= ∑ k = 0 n ∑ i = 0 c S ( c , i ) × k ! ( k − i ) ! × x k × n ! k ! × ( n − k ) ! =\large \sum\limits_{k=0}^n \sum\limits_{i=0}^c S(c,i) \times \frac{k!}{(k - i)!} \times x^k \times \frac{n!}{k! \times(n-k)!} =k=0ni=0cS(c,i)×(ki)!k!×xk×k!×(nk)!n!
= n ! × ∑ k = 0 n ∑ i = 0 c S ( c , i ) × x k 1 ( k − i ) ! × ( n − k ) ! =\large n! \times \sum\limits_{k=0}^n \sum\limits_{i=0}^c S(c,i) \times x^k \frac{1}{(k - i)!\times(n-k)!} =n!×k=0ni=0cS(c,i)×xk(ki)!×(nk)!1
= n ! × ∑ k = 0 n ∑ i = 0 c S ( c , i ) × x k 1 ( n − i ) ! × ( n − i ) ! ( k − i ) ! × ( n − k ) ! =\large n! \times \sum\limits_{k=0}^n \sum\limits_{i=0}^c S(c,i) \times x^k \frac{1}{(n - i)!} \times \frac{(n - i)!}{(k - i)!\times(n-k)!} =n!×k=0ni=0cS(c,i)×xk(ni)!1×(ki)!×(nk)!(ni)!
= n ! ∑ i = 0 c S ( c , i ) × 1 ( n − i ) ! ∑ k = i n × x k × C n − i k − i =\large n! \sum\limits_{i=0}^c S(c,i)\times \frac{1}{(n - i)!} \sum\limits_{k=i}^n \times x^k \times C_{n-i}^{k-i} =n!i=0cS(c,i)×(ni)!1k=in×xk×Cniki

= n ! ∑ i = 0 c S ( c , i ) × 1 ( n − i ) ! ∑ k = 0 n − i × x k + i × C n − i k =\large n! \sum\limits_{i=0}^c S(c,i)\times \frac{1}{(n - i)!} \sum\limits_{k=0}^{n - i} \times x^{k + i} \times C_{n-i}^{k} =n!i=0cS(c,i)×(ni)!1k=0ni×xk+i×Cnik
后面那一坨sigma就可以用二项式定理并起来
= n ! ∑ i = 0 c S ( c , i ) × 1 ( n − i ) ! × x i × ∑ k = 0 n − i × x k × C n − i k =\large n! \sum\limits_{i=0}^c S(c,i)\times \frac{1}{(n - i)!} \times x^i \times\sum\limits_{k=0}^{n - i} \times x^{k} \times C_{n-i}^{k} =n!i=0cS(c,i)×(ni)!1×xi×k=0ni×xk×Cnik
= n ! ∑ i = 0 c S ( c , i ) × 1 ( n − i ) ! × x i × ( x + 1 ) n − i =\large n! \sum\limits_{i=0}^c S(c,i)\times \frac{1}{(n - i)!} \times x^i \times(x+1)^{n-i} =n!i=0cS(c,i)×(ni)!1×xi×(x+1)ni

这个东西就可以大力求和了
code:


#include<bits/stdc++.h>
#define ll long long
using namespace std;
int mod;
ll qpow(ll x, int y) {
	ll ret = 1;
	for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
	return ret;
}
int n, x, m, a[1005];
ll S[1005][1005];
int main() {
	scanf("%d%d%d%d", &n, &x, &mod, &m);
	S[0][0] = 1;
	for(int i = 1; i <= m; i ++)
		for(int j = 1; j <= i; j ++)
			S[i][j] = (S[i - 1][j - 1] + S[i - 1][j] * j) % mod;//第二类斯特林数
	
	for(int i = 0; i <= m; i ++) scanf("%d", &a[i]);
	ll ans = 0;
	for(int c = 0; c <= m; c ++) {
		ll nn = 1;
		for(int i = 0; i <= c; nn = nn * (n - i) % mod, i ++) {
			(ans += 1ll * a[c] * S[c][i] % mod * nn % mod * qpow(x, i) % mod * qpow(x + 1, n - i) % mod) %= mod;//式子
		}
	}
	printf("%lld", ans);
	return 0;
}

信号传递

考场上没卡空间卡到自闭,最后只拿了80分 /kk
考虑拆贡献发现对于两个位置 i , j i, j i,j
如果 i < = j − − − > j − i i<=j ---> j - i i<=j>ji
i > j − − − > i ∗ k + j ∗ k i>j ---> i * k + j * k i>j>ik+jk
也就是对于每个位置,只用考虑它的系数,最后加起来就好了
系数和非常好算
考虑 g [ i ] [ S ] g[i][S] g[i][S]表示当前放的这个数为 i i i, i i i前面放的数的集合为 S S S的系数和(考场上我就是把 i i i记到了S里面,导致空间*2,炸了20分QWQ)
先设 a [ i ] [ j ] a[i][j] a[i][j]表示 i − > j i->j i>j的次数
考虑往 S S S里面加入一个数 j j j,就是 a [ i ] [ j ] ∗ k a[i][j] * k a[i][j]k(i走向j的贡献) + a [ j ] [ i ] +a[j][i] +a[j][i] (j走向i的贡献) - ( − a [ i ] [ j ] + k ∗ a [ j ] [ i ] ) (-a[i][j]+k*a[j] [i]) (a[i][j]+ka[j][i]) (减去 j j j原来在 S S S之外的贡献)

把合并一下同类项就是 g [ i ] [ S ] = g [ i ] [ S / { j } ] + a [ i ] [ j ] ∗ ( k + 1 ) − a [ j ] [ i ] ∗ ( k − 1 ) g[i][S] = g[i][S /\{j\}]+a[i][j] * (k+1) - a[j][i] * (k - 1) g[i][S]=g[i][S/{j}]+a[i][j](k+1)a[j][i](k1)
f [ S ] 表 示 前 ∣ S ∣ 位 放 的 数 的 集 合 , 显 然 f [ S ] = f [ S / { i } ] + g [ i ] [ S / { i } ] f[S]表示前|S|位放的数的集合,显然f[S] = f[S/ \{ i\}] + g[i][S / \{i\}] f[S]Sf[S]=f[S/{i}]+g[i][S/{i}]
这样空间和时间复杂度就只有 O ( m ∗ 2 m ) O(m * 2^m) O(m2m)
这样就可以过了
code:


#include<bits/stdc++.h>
#define M 23
#define N (1 << M)
using namespace std;
int n, m, k, a[M + 5][M + 5], size[N + 5], g[M][(N >> 1) + 5], lg[N + 5], f[N + 5];
int main() {
	scanf("%d%d%d", &n, &m, &k);
	int x = -1;
	while(n --) {
		int y;
		scanf("%d", &y); y --;
		if(x != -1) a[x][y] ++;
		x = y;
	}
	lg[1] = 0; size[1] = 1;
	for(int S = 2; S < (1 << m); S ++) lg[S] = lg[S >> 1] + 1, size[S] = size[S >> 1] + (S & 1);
	for(int i = 0; i < m; i ++) {
		for(int j = 0; j < m; j ++) if(i != j) g[i][0] += a[j][i] * k - a[i][j];
		for(int S = 1; S < (1 << (m - 1)); S ++) {
			int jj = S & (- S);
			int j = lg[jj];
			j += (j >= i);
			g[i][S] = g[i][S ^ jj] + a[i][j] * (1 + k) - a[j][i] * (k - 1);
		}
	}
	memset(f, 0x3f, sizeof f);
	f[0] = 0;
	for(int S = 1; S < (1 << m); S ++) 
		for(int j = 0; j < m; j ++) if((S >> j) & 1) 
			f[S] = min(f[S], f[S ^ (1 << j)] + g[j][S & ((1 << j) - 1) | (S >> (j + 1) << j)] * size[S]);//乘上size[S]是因为放在第|S|位
	printf("%d", f[(1 << m) - 1]);
	return 0;
}

to be continue……

posted @ 2020-11-30 22:17  lahlah  阅读(34)  评论(0编辑  收藏  举报