逛了一圈发现没有我的做法,就写一个吧,详情可以参考我的b站视频******************************************
哎呀呀,这种一眼就能看出是组合数学的题目,居然还要本天才翔子出马?你们这些杂鱼的大脑难道和二进制数组里的 0 一样,完全没有存在的价值吗?呵呵~
既然你们求知欲这么旺盛(其实是太笨了吧?),那我就勉为其难地给你们这群逊毙了的家伙写篇题解。好好盯着看,这可是天才的恩赐!
📊 翔子的天才课堂:二进制中位数的秘密
🧐 核心逻辑:中位数才不是随便当的!
听好了,笨蛋杂鱼们!这道题的数组只有 0 和 1。
- 中位数的本质:对于长度为 的子序列,中位数是 1 的充分必要条件是——这个子序列里至少有 个 1。
- 固定中位数的策略:我们把原数组从小到大排个序(虽然里面全是 0 和 1,但排序后 0 都在左边, 1 都在右边)。
- 计数大法:
- 假设我们要让第 个位置的数 成为中位数。
- 我们需要在它的左边( 个位置)选出 个数。
- 我们需要在它的右边( 个位置)选出 个数。
- 这样总共就选了 个数,且 刚好在中间。
- 既然只有 的时候才会对总和有贡献,那我们只需要算 时的组合数就行了!
这种 的预处理加 的遍历,连杂鱼都能跑通,要是你还写错,建议直接退出代码界呢~
💻 毫无难度的 C++ 代码
这种基础的逆元和阶乘预处理,要是杂鱼不会写,翔子真的会笑出声的哦!
#include <bits/stdc++.h>
#define il inline
#define double long double
using namespace std;
using ll = long long;
using ull = unsigned long long;
using int128 = __int128_t;
const ll N = 2e5 + 5, mod = 1e9+7, inf = 2e18;
const double eps = 1e-9;
double PI = 3.1415926;
// 杂鱼才需要写注释,但我还是帮你们写了,感谢我吧!
ll quick_mi(ll a,ll b){
ll ans=1;
while(b){
if(b&1){
ans=ans*a%mod;
}
b>>=1;
a=a*a%mod;
}
return ans;
}
// 逆元都不会算的杂鱼可以去重修小学数学了
ll inv(ll n){
return quick_mi(n,mod-2);
}
vector<ll>fact(N,1),inv_fact(N);
// 组合数公式 C(n, m),杂鱼记住了吗?
ll C(ll n,ll m){
if(m<0||m>n)return 0; // 选不出来就是0,和杂鱼的智商一样
return fact[n]*inv_fact[m]%mod*inv_fact[n-m]%mod;
}
il void solve() {
int n,k;
cin>>n>>k;
vector<ll>a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
// 排序后 1 都在右边,方便我们固定中位数
sort(a.begin()+1,a.end());
ll ans=0;
ll need=k/2;
for(int i=1;i<=n;i++){
// 只有 a[i]=1 才有贡献,杂鱼要是这里写错就逊爆了
(ans+=C(i-1,need)*C(n-i,need)*a[i]%mod)%=mod;
}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
// 预处理阶乘,为了拯救杂鱼的时间复杂度
for(int i=1;i<N;i++){
fact[i]=fact[i-1]*i%mod;
}
inv_fact[N-1]=inv(fact[N-1]);
for(int i=N-2;i>=0;i--){
inv_fact[i]=inv_fact[i+1]*(i+1)%mod;
}
cin >> t;
while (t--){
solve();
}
return 0;
}
🐍 慢吞吞的 Python 代码
虽然 Python 慢得像杂鱼爬行,但逻辑还是一样简单的呢。
import sys, math, queue, itertools, heapq
from collections import deque
from array import array
from bisect import bisect_right
# 这个递归深度,杂鱼的大脑能承受吗?
sys.setrecursionlimit(1145141919)
input = sys.stdin.readline
def read():
line = sys.stdin.readline()
if not line:
return []
return list(map(int, line.split()))
mod = 10**9 + 7
N = 2 * (10**5) + 5
def quick_mi(a, b):
ans = 1
while b:
if b & 1:
ans = ans * a % mod
b >>= 1
a = a * a % mod
return ans
def inv(n):
return quick_mi(n, mod - 2)
fact = [1] * N
inv_fact = [0] * N
def C(n, m):
if m < 0 or m > n:
return 0
return fact[n] * inv_fact[m] * inv_fact[n - m] % mod
def solve():
n, k = read()
need = k // 2
a = [0] + read()
# 居然要手动排序,Python 真是麻烦呢,呵呵~
a.sort(key=lambda x: x)
ans = 0
for i in range(1, n + 1):
# 左右两边各选 need 个,中间坐个 1
ans += a[i] * C(i - 1, need) * C(n - i, need)
ans %= mod
print(ans)
def main():
# 预处理是给杂鱼最后的仁慈
for i in range(1, N):
fact[i] = fact[i - 1] * i % mod
inv_fact[N - 1] = inv(fact[N - 1])
for i in range(N - 2, -1, -1):
inv_fact[i] = inv_fact[i + 1] * (i + 1) % mod
line = sys.stdin.readline()
if not line: return
t = int(line)
for _ in range(t):
solve()
if __name__ == "__main__":
main()
🙄 翔子的最后嘲讽
看明白了吗?这道题的精髓就是:只要你不是个连组合数都不会算的杂鱼,你就能过!
固定中位数位置,左右两边各选一半,这么简单的逻辑要是还要我讲第二遍,我就要把你的准考证撕掉喽~ 呵呵。赶紧去提交吧,别在这里碍眼了!

京公网安备 11010502036488号