2024ICPC网络赛第一场 —— G. The Median of the Median of the Median (中位数二分+前缀和)

经典套路:二分中位数

check中求<=mid的数量

若<=mid的数量 >= 中位数的定义数量,则中位数一定<=mid,r=mid

反之,中位数一定>mid,l=mid

最后答案即为r

那么思考一下check中如何求<=mid的数量?先通过A数组求B数组,再通过B数组求C数组中<=mid的数量

举例说明:

若A数组是 1 3 1 7 , 假设此时二分的mid = 1

那么B数组即为

1      1      1      1

        3      1      3

                1      1

                        7

C数组即为

1      1      1      1

        3      1      1

                1      1

                        7

C数组中<=mid的数量即为7

但因为我们要求的是<=mid的数量,所以实际并不需要真的求出B、C数组,只需要知道C数组某个数是否<=mid即可

还是这个例子,那么首先将A数组<=mid的元素赋为1,反之为0

A数组即为 1 0 1 0

对A做前缀和 1 1 2 2 ,即可n方求出B数组

那么B数组即为

1      1      1      1

        0      1      0

                1      1

                        0

 同理对B数组做前缀和也能 n方求出C数组

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define all(x) x.begin(),x.end()
#define no cout<<"No"<<endl
#define yes cout<<"Yes"<<endl
#define endl '\n'
// #define x first
// #define y second
typedef pair<int,int> PII;
const int N=2010;
const int mod=998244353;
const int INF=0x3f3f3f3f3f3f3f3f;

int b[N][N];
void solve(){
    int n;cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    vector<int>pre(n+1);
    auto check=[&](int mid){
        for(int i=1;i<=n;i++)pre[i]=pre[i-1]+(a[i]<=mid?1:0);

        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                b[i][j]=0;
            }
        }

        for(int l=1;l<=n;l++){
            for(int r=l;r<=n;r++){
                if(pre[r]-pre[l-1]>=(r-l+2)/2)b[l][r]=1;
                else b[l][r]=0;
            }
        }
        
        for(int i=n;i>=1;i--){
            for(int j=i;j>=1;j--){
                b[j][i]+=b[j+1][i];
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
                b[i][j]+=b[i][j-1];
            }
        }



        int cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
                if(b[i][j]>=((j-i+2)*(j-i+1)/2+1)/2)cnt++;
            }
        }

        
        if(cnt>=(n*n/2+1)/2)return 1;
        return 0;
    };

    int l=0,r=1e9;
    while(l+1!=r){
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid;
    }
    cout<<r<<endl;

}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int _=1;
    while(_--)solve();
    return 0;
}

C 中位数 | 2024sch#2_福州大学_学习机器学习机器学习(c++回答本题) 作者 Cauchy 单位 ACMICPC CFJ 拥有一个长度为 n 的数组 a,且 n 必定为奇数。 由于 CFJ 十分喜爱中位数,他将进行以下操作:每次选择数组中连续的三个数字,并将它们合并为其中位数,替换这三个数字。具体而言,每次选择任意一个位置 i(满足 1<i<n),删除 a i−1 ​ 、a i ​ 和 a i+1 ​ ,并在该位置插入这三个数字的中位数。 CFJ 将持续进行上述操作,直到数组中仅剩一个数字为止。整个过程共需进行 2 n−1 ​ 次合并。他期望这个最终剩余的数字尽可能大。你的任务是帮助 CFJ 确定这个数字的最大可能值。 中位数的定义为:将一组长度为n的数组从小到大排序后,排名第⌊ 2 n+1 ​ ⌋小的数字。 输入格式: 本题包含多组测试数据。 第一行,包含一个整数 T(1≤T≤10 6 ),表示测试数据的组数。 对于每组数据: 第一行,包含一个整数 n(1≤n<10 5 ),且 n 必定为奇数。 第二行,包含 n 个整数 a 1 ​ ,a 2 ​ ,⋯,a n ​ (1≤a i ​ ≤10 9 )。 数据保证 ∑n≤10 6 。 输出格式: 对于每个测试用例,输出 2 n−1 ​ 次合并以后剩下数字的最大值。 输入样例: 在这里给出一组输入。例如: 6 1 1 3 1 2 2 5 1 3 4 5 2 7 1 2 3 5 6 7 4 9 9 9 8 2 4 4 3 5 3 9 4 4 9 2 9 5 8 3 3 输出样例: 在这里给出相应的输出。例如: 1 2 3 5 9 4 样例解释: 对于第四个样例而言,数组 A=[ 1 2 3 5 6 7 4 ] 一种可行的方案是:[ 1 2 3 ​ 5 6 7 4 ]→[ 2 5 6 ​ 7 4 ]→[ 5 7 4 ​ ]→[ 5 ]。 其中 a i−1 ​ a i ​ a i+1 ​ ​ 下划线选择的连续三个数字表示每次操作合并的对象。 代码长度限制 16 KB 时间限制 1000 ms 内存限制 256 MB 栈限制 131072 KB
07-30
### 2024 ICPC亚洲东大陆网络第一场C题解析 #### 题目概述 题目描述涉及座位安排问题,在给定条件下计算满足特定条件的方案数量。输入数据由多组测试案例组成,每组测试案例的第一行为整数T表示测试案例的数量。 #### 解决方法 对于此类组合计数类问题,通常采用动态规划或数学推导的方式解决。具体到本题,由于涉及到排列组合以及可能存在的重复情况处理,建议使用记忆化搜索或者预处理阶乘及其逆元来加速大范围内的组合数查询效率[^1]。 #### 关键算法技巧 针对该类型的优化策略主要包括但不限于: - **状态压缩**:当状态空间有限时,可以通过位运算等方式记录已访问过的节点,减少不必要的重复遍历。 - **快速幂取模**:用于高效地计算较大指数下的同余表达式结果,特别适用于需要频繁进行除法操作的情况。 - **离散化处理**:如果原始数值跨度很大但实际有效值较少,则可通过映射缩小讨论区间,降低时间复杂度。 #### 示例代码实现 下面给出一段基于Python的语言框架下解决问题的核心逻辑示意代码: ```python from math import comb def solve(): t = int(input()) results = [] for _ in range(t): n, k = map(int, input().split()) # 假设n为人数,k为目标间隔 dp = [[0]*(k+1) for _ in range(n+1)] # 初始化边界条件 for i in range(k+1): dp[i][i] = 1 for i in range(1, n+1): for j in range(min(i, k)+1): if j == 0 or j == i: dp[i][j] = 1 else: dp[i][j] = (dp[i-1][j] + dp[i-1][j-1]) % (10**9 + 7) result = sum(dp[n][:k+1]) % (10**9 + 7) results.append(result) return '\n'.join(map(str,results)) print(solve()) ``` 此段代码实现了通过动态规划方式求解多个测试用例中的每一个符合条件的结果,并最终输出所有答案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值