Solution
A
无脑 dp \text{dp} dp 即可。
B
花了好长时间才做出来。
假设 T T T 依次选择了橘子 t 1 , t 2 , ⋯ , t k t_1,t_2,\cdots,t_k t1,t2,⋯,tk, A A A 依次选择了橘子 a 1 , a 2 , ⋯ , a n − k a_1,a_2,\cdots,a_{n-k} a1,a2,⋯,an−k,考虑构造一组满足上述要求的方案。
首先,一定是 T T T 先选,于是他先拿了 t 1 t_1 t1。接下来的一个橘子,必须是 t 2 t_2 t2 或 a 2 a_2 a2,但是若选择了 t 2 t_2 t2,那么它就被 A A A 拿了,与分配方案不符。于是,我们不得不选择 a 1 a_1 a1。接下来,若 T T T 的权值和大于 A A A 的权值和,就放 a i a_i ai,否则放 t j t_j tj。只有这样,才能保证方案合法。
从而,若钦定了 ( t , a ) (t,a) (t,a),那么就只有 1 1 1 种选法了。更进一步的,若我们钦定了 ( t ′ , a ′ ) (t',a') (t′,a′),其中 t ′ , a ′ t',a' t′,a′ 分别表示 T , A T,A T,A 两人选出橘子的集合(没有顺序限制),那么就会有 ∣ t ′ ∣ ! × ∣ a ′ ∣ ! |t'|! \times |a'|! ∣t′∣!×∣a′∣! 的贡献。从而,答案即为,所有权值和为 s 2 \frac {s} {2} 2s 的集合大小的阶乘之和,其中 s = ∑ i = 1 n W i s=\sum_{i=1}^n W_i s=∑i=1nWi。
于是就可以愉快地 dp \text{dp} dp 啦。
令 f i , j , k f_{i,j,k} fi,j,k 表示,目前看到第 i i i 个位置,总共选了 j j j 个,且选出的权值和为 k k k。有转移如下:
f i , j , k → f i + 1 , j + 1 , k + W i + 1 f i , j , k → f i + 1 , j , k f_{i,j,k} \to f_{i+1,j+1,k+W_{i+1}} \\ f_{i,j,k} \to f_{i+1,j,k} fi,j,k→fi+1,j+1,k+Wi+1fi,j,k→fi+1,j,k
答案即为
∑ i = 1 n f n , i , s 2 i ! \sum_{i=1}^n f_{n,i,\frac s 2}i! i=1∑nfn,i,2si!
特别的,若 s ≡ 1 ( m o d 2 ) s \equiv 1 \pmod 2 s≡1(mod2),那么不执行上述 dp \text{dp} dp 并直接输出 − 1 -1 −1。
总复杂度 O ( n 2 s ) O(n^2 s) O(n2s),本题被解决。应该和官方题解差不多吧。
C
考场上不知道在想什么,写了一个暴力找规律然后发现了规律,结果不会表达出来,甚至写出来了一个非常复杂的式子,导致没有在考场上切掉本题。菜得真实。
算法一
考虑枚举 P P P,并判断它是否会最终变成 P ′ P' P′。
关键在于构造一个最优方案。不难得到: 每次找到一个最小的 i i i 使得 [ 1 , i − 1 ] [1,i-1] [1,i−1] 中比 P i P_i Pi 大的数超过 k k k 个且 P i − 1 ′ > P i ′ P'_{i-1}>P'_i Pi−1′>Pi′,并交换 ( i − 1 , i ) (i-1,i) (i−1,i)。
这个方案肯定是能够使 P P P 最终合法的,但是它是否是最优的呢?
考虑交换次数的下界是多少。令
c
n
t
i
cnt_i
cnti 表示,初始时
[
1
,
i
−
1
]
[1,i-1]
[1,i−1] 中,有多少个
j
j
j 使得
P
j
′
>
P
i
′
P'_j>P'_i
Pj′>Pi′。对于每次交换,至多会有一个
c
n
t
i
cnt_i
cnti 被减去了
1
1
1,于是下界就是
∑
i
=
1
n
max
(
c
n
t
i
−
K
,
0
)
\sum_{i=1}^n \max(cnt_i-K,0)
i=1∑nmax(cnti−K,0)
可以证明,我们构造的操作方案恰好达到了这个下界。为什么呢?因为,每操作一次,均恰好有一个 c n t i cnt_i cnti 减去了 1 1 1,且每次都能找到一个合法的位置 i i i 并进行操作。这样一来,我们的操作方案就是最优的啦。
由于共有 n 2 n^2 n2 轮,每轮都要在 O ( n 2 ) O(n^2) O(n2) 的代价内找到对应的 i i i 并交换 ( i − 1 , i ) (i-1,i) (i−1,i),所以复杂度是惊人的 O ( n ! n 4 ) O(n! n^4) O(n!n4)。
算法二
现在关键在于,对于某一个初始格局 P ′ P' P′,快速算出其最终的格局长什么样。
考虑对于某一个 P i ′ P'_i Pi′,它最终到了哪里。不难发现,一旦它开始向左移动,那么它就会移动到左边第 K + 1 K+1 K+1 个比它大的位置左边,并永远停下来。换言之,算法一中的操作流程与下面的流程是等价的。
for (int i=2;i<=n;i++){
int p=0,cnt=0,now=i;
//p:向左移动的次数 cnt:左边比它大的数的个数 now:无实际意义
for (int j=1;j<i;j++){
if (q[j]>q[i]) cnt++;
if (cnt==k+1){p=i-j;break;}//找到第 k+1 个比它大的,需要移动到它的左边
}
for (int j=1;j<=p;j++) swap(q[now],q[now-1]),now--;//进行若干次连续的移动
}
复杂度 O ( n ! n 2 ) O(n! n^2) O(n!n2)。
算法三
算法一与算法二都不能在多项式时间复杂度内完成计算,但是它们能给我们很大的启发。请看下面的引理:
Lemma
对于在给定序列 P P P 中的某个位置 P i P_i Pi,且第 K K K 个大于 P i P_i Pi 的位置为 j j j,那么 P ′ P' P′ 中 P i P_i Pi 出现的位置一定在 P j P_j Pj 之后。
这是充分必要条件。
从而,我们只需要找到所有 y i = K y_i=K yi=K 的位置,固定它们的相对顺序,并把其他位置给依次插入进来。根据乘法原理不难得到,答案即为每个数可以被插入的位置数量,则
a n s = ∏ i = 1 n [ y i = K ] ( n − i + 1 ) ans=\prod_{i=1}^n [y_i=K](n-i+1) ans=i=1∏n[yi=K](n−i+1)
采用树状数组计算出 y y y,然后扫描一遍即可计算出答案。总复杂度 O ( n log n ) O(n \log n) O(nlogn)。