省选联考 2020 A 卷
省赛虽然炸了,但题解还是要写滴(笑)
第 200 篇 b l o g 祭 ! ! \Huge 第200篇blog祭!! 第200篇blog祭!!
组合数问题
题意简单明了
首先要看出要把多项式的每一项分别算
第
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}
ac∗k=0∑nkc×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=0∑mS(m,i)×(n−i)!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=0∑ni=0∑cS(c,i)×(k−i)!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=0∑ni=0∑cS(c,i)×(k−i)!k!×xk×k!×(n−k)!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=0∑ni=0∑cS(c,i)×xk(k−i)!×(n−k)!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=0∑ni=0∑cS(c,i)×xk(n−i)!1×(k−i)!×(n−k)!(n−i)!
=
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=0∑cS(c,i)×(n−i)!1k=i∑n×xk×Cn−ik−i
=
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=0∑cS(c,i)×(n−i)!1k=0∑n−i×xk+i×Cn−ik
后面那一坨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=0∑cS(c,i)×(n−i)!1×xi×k=0∑n−i×xk×Cn−ik
=
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=0∑cS(c,i)×(n−i)!1×xi×(x+1)n−i
这个东西就可以大力求和了
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−−−>j−i
i
>
j
−
−
−
>
i
∗
k
+
j
∗
k
i>j ---> i * k + j * k
i>j−−−>i∗k+j∗k
也就是对于每个位置,只用考虑它的系数,最后加起来就好了
系数和非常好算
考虑
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]+k∗a[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]∗(k−1)
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]表示前∣S∣位放的数的集合,显然f[S]=f[S/{i}]+g[i][S/{i}]
这样空间和时间复杂度就只有
O
(
m
∗
2
m
)
O(m * 2^m)
O(m∗2m)
这样就可以过了
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……