codeforce 939E 差分+二分/三分

本文解析了CodeForces 939E题目的算法思路,通过数学推导介绍了如何利用二分法求解最大值问题,特别关注于函数极值的寻找方法。

传送门:http://codeforces.com/problemset/problem/939/E

题意:

有两种操作:

(1)在集合S中插入一个元素

(2)输出最大的 Max(s)mean(s) M a x ( s ) − m e a n ( s ) ——其中s是集合的子集,Max(s)表示s中最大的元素,mean(s)表示s的平均值

(3) 输入保证插入的元素比原集合中的所有元素都要大

分析:

(1)有一个前提条件:所选的最优的集合s必然包含集合S中最大的元素,其他元素必然是S的一个前缀

(2)函数 Max(s)mean(s) M a x ( s ) − m e a n ( s ) 有极值

(3)对于有极值的函数考虑用二分或者三分的思路求解

题解(二分思路):

mi=anan+i1j=0aji+1 m i = a n − a n + ∑ j = 0 i − 1 a j i + 1

mi+1mi m i + 1 − m i = an+i1j=0ajai(i+1) a n + ∑ j = 0 i − 1 a j − a i ( i + 1 ) (此处去除了分母,因为分母对于函数的正负号没有影响,而二分过程只与函数的正负号有关,故可以去除分母)

f(i)=mi+1mi f ( i ) = m i + 1 − m i

可以用前一项减去后一项来证明证明 f(i) f ( i ) 是非递减的

二分找到最小的 i i 使得 f(i)<=0 Max(s)mean(s) M a x ( s ) − m e a n ( s ) 取得最大值

代码:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

long long sum[500005];
long long a[500005];
int main()
{
    int q;
    cin>>q;
    int cnt=0;
    memset(a,0,sizeof a);
    memset(sum,0,sizeof sum);
    double ans=0;
    while(q--)
    {
        int op;
        cin>>op;
        if(op==1)
        {
            cin>>a[cnt];
            int l=0,r=cnt;
            if(cnt>=1)
                sum[cnt]=sum[cnt-1]+a[cnt];
            else
                sum[cnt]=a[cnt];
            while(l<r)
            {
                int mid=(l+r)/2;
                long long fi;
                if(mid!=0)
                    fi=a[cnt]+sum[mid-1]-a[mid]*(mid+1);
                else
                    fi=a[cnt]-a[mid]*(mid+1);
                if(fi<=0) r=mid;
                else l=mid+1;
            }
            double avg=1.0*(sum[r-1]+a[cnt])/(r+1);
            double tmp=a[cnt]-avg;
            ans=max(ans,tmp);
            cnt++;
        }else{
            printf("%.10f\n",ans);
        }
    }
    return 0;
}

三分思路:不做差分,直接找函数的最大值,网上的题解大多为三分,故不做详细分析

<think>好的,我现在需要帮助用户制定在Codeforces上达到1200分的策略和技巧。首先,用户之前已经询问过类似的问题,所以我得确保回答的结构清晰,并且包含实用的建议。根据系统指令,我需要用中文回答,正确使用LaTeX格式,还要生成相关问题。 首先,用户的目标是达到1200分,这属于入门到中级的过渡阶段。通常,这个分段的问题集中在Div.2的A、B题,有时可能涉及C题。因此,我需要强调基础算法和数据结构的掌握,比如贪心、模拟、排序、二分查找等。 接下来,用户可能需要具体的学习方法,比如刷题策略。这里可以推荐Codeforces的特定题库,比如按照评分筛选题目,从800-1200分的题目开始练习。同时,参加虚拟比赛和定期训练也是关键点。 另外,比赛技巧也很重要,比如快速读题、时间管理、避免罚时等。需要提醒用户注意这些细节,比如先解决简单题,不要卡在难题上。 代码实现方面,用户可能需要优化模板,比如快速输入输出,这在C++中常见,但用户可能使用Python,所以可以建议使用sys.stdin.readline来加速输入。 然后,我需要考虑用户可能的薄弱环节,比如数学基础或者特定算法,比如数论中的模运算、质数判断,或者动态规划的基础问题。这部分需要简要提及,并给出例子,比如如何高效判断质数,或者斐波那契数列的动态规划解法。 后,生成相关问题时要围绕用户可能进一步需要的内容,比如如何突破瓶颈、特定算法的学习资源、时间管理技巧等。确保问题有针对性,能够引导用户深入下一步的学习。 检查一下是否需要引用,根据示例中的引用,可能不需要添加,但如果有必要可以加入相关资源推荐。同时,确保所有数学表达式用$...$格式,例如时间复杂度O(n log n)可以写成$O(n \log n)$,独立公式用$$...$$,比如动态规划的递推式。 现在组织内容,确保每个部分有清晰的标题,策略分点,代码示例正确,并且语言简洁。可能还需要提醒用户注意题目分类和总结错误,这些都是提高的关键。</think># Codeforces 达到 1200 分的策略与技巧 ## 一、基础能力强化 1. **算法优先级** 重点掌握:贪心、模拟、排序、二分查找、简单动态规划(如背包问题)、基础数论(模运算、质数判断)。 例如二分模板需熟练写出: ```python def binary_search(arr, target): left, right = 0, len(arr)-1 while left <= right: mid = (left + right) // 2 if arr[mid] < target: left = mid + 1 else: right = mid - 1 return left ``` 2. **时间复杂度控制** - 数据规模 ≤ $10^3$:允许 $O(n^2)$ 算法 - 数据规模 ≤ $10^5$:必须使用 $O(n \log n)$ 或更低复杂度 ## 二、针对性训练方法 1. **题目选择策略** - 使用Codeforces题库过滤器:`Difficulty: 800-1200` - 按标签分类训练:每周专注1-2个算法类型 2. **虚拟参赛实践** - 每周至少2场虚拟比赛(推荐Div.2) - 赛后分析:使用Codeforces的`PRACTICE`功能重做未通过题目 ## 三、比赛实战技巧 1. **解题顺序优化** - 开赛前5分钟快速浏览所有题目 - 建议顺序:A → B → D → C(根据实际难度动态调整) 2. **代码模板预置** 准备常用代码片段加速编写: ```python import sys from collections import defaultdict def main(): input = sys.stdin.readline n = int(input()) arr = list(map(int, input().split())) # 解题代码 if __name__ == "__main__": main() ``` ## 四、关键数学模型 1. **数论基础** - 快速幂算法:计算 $a^b \mod m$ 时使用 $$a^b \mod m = \begin{cases} 1 & b=0 \\ (a^{b/2})^2 \mod m & b \text{为偶数} \\ a \cdot (a^{(b-1)/2})^2 \mod m & b \text{为奇数} \end{cases}$$ 2. **动态规划模型** 经典斐波那契数列DP实现: ```python def fib(n): dp = [0] * (n+1) dp[1] = 1 for i in range(2, n+1): dp[i] = dp[i-1] + dp[i-2] return dp[n] ``` ## 五、效率提升工具 1. **调试技巧** - 边界测试:n=0/1, 数组全相同元素等极端情况 - 使用Python的`pdb`模块进行断点调试 2. **资源推荐** - [Errichto的算法教学频道](https://www.youtube.com/c/Errichto)(适合可视化学习) - Codeforces EDU板块的《Binary Search》课程[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值