题目链接:https://codeforces.com/contest/841
A - Generous Kefa
签到题,用一下鸽巢原理。
B - Godsend
题意:有一个n个元素的正整数序列,两个玩家轮流操作,玩家A先操作。玩家A每次可以选连续的一段元素,满足:他们的和为奇数,然后删除选择的元素,玩家B每次可以选连续的一段元素,满足:他们的和为偶数,然后删除选择的元素。每次删除完元素过后,剩余的部分会重新连接在一起。谁无法操作谁就输。问最优策略下谁会赢。
题解:显然假如全部元素的和为奇数,就是A赢。否则假如全部元素都是偶数,那么就是B赢。会不会有B赢的其他情况呢?既然是B赢,那么必然是B操作最后一步,也就是最后一步必定全部元素的和为偶数,由于是A先操作,假如一开始全部元素的和为偶数,且至少有一个奇数,已知就是至少有两个奇数,那么A肯定取走奇数的一部分,剩下的一部分和也是奇数,也就是只有当A起手不能操作的时候B才能赢。然后马上就能发现必胜策略:把最后一个奇数左边的一段在第一步都拿走。
C - Leha and Function
题意:定义一个函数 (F(n,k)) 表示在 ([1,n]) 中选 (k) 个元素形成的子集,然后取每个子集的最小值的数学期望。给两个长度都是 (m) 的正整数数组 (A) 和 (B) ,满足 (min(A)geq max(B)) ,重新排列 (A) ,使得 (sumlimits_{i=1}^{m}F(A'_i,B_i)) 最大,这里的 (A') 表示重新排列之后的数组 (A) 。
题解:看了一下样例貌似是大的配小的这样排序,但是不知道会不会有坑。用微扰法观察:设 (A_1leq A_2) 且 (B_1leq B_2) ,则 (F(A_1,B_1)+F(A_2,B_2)leq F(A_1,B_2)+F(A_2,B_1)) 是否成立?先考虑 (F(n,k)) 本身有什么性质,首先当 (k) 不变且 (n) 变大,答案显然变大;当 (n) 不变 且 (k) 变大,就感觉不是特别明显。考虑
(F(6,1)=frac{1}{6}(1+2+3+4+5+6)=frac{7}{2})
(F(6,2)=frac{1}{15}(1*5+2*4+3*3+4*2+5*1+6*0)=frac{1}{15}(5+8+9+8+5+0)=frac{7}{3})
(F(6,3)=frac{1}{C_6^3}(1*C_5^2+2*C_4^2+3*C_3^2+4*C_2^2+5*C_1^2+6*C_0^2)=frac{7}{4})
(F(6,4)=frac{1}{C_6^4}(1*C_5^3+2*C_4^3+3*C_3^3+4*C_2^3+5*C_1^3+6*C_0^3)=frac{7}{5})
(F(6,5)=frac{1}{C_6^5}(1*C_5^4+2*C_4^4+3*C_3^4+4*C_2^4+5*C_1^4+6*C_0^4)=frac{7}{6})
(F(6,6)=frac{1}{C_6^6}(1*C_5^5+2*C_4^5+3*C_3^5+4*C_2^5+5*C_1^5+6*C_0^5)=frac{7}{7})
貌似 (F(n,k)=frac{n+1}{k+1}) ,假如这个式子成立,就能够说明 (F(A_1-1,B_1-1)+F(A_2-1,B_2-1)=frac{A_1B_2+A_2B_1}{B_1B_2}leq F(A_1-1,B_2-1)+F(A_2-1,B_1-1)=frac{A_1B_1+A_2B_2}{B_1B_2}) 。所以贪心的策略确实就是上述的大数配小数。不过这个期望是怎么准确计算呢?从这个求和式貌似看不出什么结果,官方题解貌似是另一种算法。
struct Node {
int id, val;
} A[200005], B[200005];
bool cmp(const Node &n1, const Node &n2) {
return n1.val < n2.val;
}
bool cmp2(const Node &n1, const Node &n2) {
return n1.id < n2.id;
}
void test_case() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &A[i].val);
A[i].id = i;
}
for(int i = 1; i <= n; ++i) {
scanf("%d", &B[i].val);
B[i].id = i;
}
sort(A + 1, A + 1 + n, cmp);
sort(B + 1, B + 1 + n, cmp);
for(int i = 1; i <= n; ++i)
A[i].id = B[n + 1 - i].id;
sort(A + 1, A + 1 + n, cmp2);
for(int i = 1; i <= n; ++i)
printf("%d%c", A[i].val, "
"[i == n]);
}
奇怪的知识增加了:由上面的算法可知: (F(n,k)=frac{sumlimits_{i=1}^{n}i*C_{n-i}^{k-1}}{C_n^k}=frac{n+1}{k+1})
即:
(sumlimits_{i=1}^{n}i*C_{n-i}^{k-1}=frac{n+1}{k+1}C_n^k)
(sumlimits_{i=1}^{n}i*C_{n-i}^{k-1}=C_{n+1}^{k+1})
(sumlimits_{i=1}^{n}C_i^1*C_{n-i}^{k-1}=C_{n+1}^{k+1})
但这是为什么呢?有一种非常扭曲的理解:左边是先确定选出的第2个元素的位置,然后在左边选1个元素作为第1个元素,在右边选k-1个元素,方法之间是独立的,可以求和。