Codeforces Round #703 (Div. 2)

Codeforces Round #703 (Div. 2)

A. Shifting Stacks

题目大意

给定序列\(a\)\(a_i\)可以传任意数给\(a_{i + 1}\),要求序列最终严格递增。问是否可以。

思路

可以贪心做,保证严格递增之后将多余的数全部传下去。

仔细研究得出结论,最优为\(\{0, 1, \cdots,n - 1\}\),因此只要保证任意位置的前缀和大于最优序列即可。

\[\sum_{i=0}^{k}a_i \ge\dfrac{n\cdot(n-1)}{2} \]

代码

💎问题A代码💎

    #include 
    using namespace std;
    #define DEBUG 0
    #define int long long
    #define all(x) x.begin(), x.end()
    #define sz(x) (int(x.size()))
    #define vt std::vector
    #define pb push_back
    using ll = long long;
    using db = double;
    using pii = pair;
    using pll = pair;
    const int maxn = 1e3 + 50;
    const int inf = 0x3f3f3f3f3f;
    template
    inline void wpr(Args... args) { std::cout << '\n'; }
    template
    void wpr(T val, Args... args) { std::cout << val << " "; wpr(args...); }
    void solve(){
        int n, tot = 0, ok = 1; 
        std::cin >> n;
        for (int i = 0; i < n; ++ i){
            int rd;
            std::cin >> rd;
            tot += rd;
            if (tot < (i * (i + 1) / 2)) ok = 0;
        }
        std::cout << (ok ? "yes" : "no") << "\n";
    }
    signed main(){
        ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        int t = 1;
        std::cin >> t;
        while (t--) solve();
        return 0;
    }

B. Eastern Exhibition

题目大意

There are \(n\) houses, you should find some points so that the summary distance from all the houses to the exhibition is minimal. For each case output the number of different positions for the exhibition. Note : the distance is Manhattan Distance .

思路

此题考查的是绝对值不等式。

\[\begin{aligned} &\min(|x-a_1| + |x-a_2| + \cdots+|x-a_n|)\quad \\ &\text{*when x = the medium of sequence }a \end{aligned} \]

当序列长度为奇数时,显然中位数为确定的,那么答案只有一个。

当序列长度为偶数时,则最小值在\(x\)在范围\(a_{\frac{n}{2}} \sim a_{\frac{n}{2}-1}\)内皆满足。

因此当\(n\)为偶数时,答案为\(x,y\)轴可选区间长度的乘积。

代码

💎问题B代码💎

    void solve(){
        int n;
        std::cin >> n;
        vt fx(n), fy(n);
        for (int i = 0; i < n; ++ i) std::cin >> fx[i] >> fy[i];
        sort(all(fx)), sort(all(fy));
        if (n & 1) std::cout << 1 << "\n";
        else std::cout << 1ll * (fx[n / 2] - fx[n / 2 - 1] + 1) * (fy[n / 2] - fy[n / 2 - 1] + 1) << "\n";
    }

C2. Guessing the Greatest (hard version)

题目大意

Find the position of the maximum element in the array in no more than \(20\) queries. For each query you can ask the position of the second maximum element in a subsegment \(a[l..r]\).

思路

不难分析出是一个二分题,实际上交互一般都是二分

由于我们只能询问第二大的值,我们首先询问全局第二大的值并将其设为端点,然后再二分寻找另一端点。保证该端点恰好可以使得区间内的第二大值为全局第二大值(也就是该端点为最大值)。

首先讨论最大值在左还是在右,因为需要讨论端点情况。

代码

💎问题C代码💎

    inline int query(int l, int r){
        std::cout << "? " << l << " " << r << endl;
        int res; std::cin >> res;
        return res;
    }
    void solve(){
        int n; 
        std::cin >> n;
        int l = 1, r = n;
        int p = query(l, r);
        if (p != 1 and p == query(1, p)){
            l = 1, r = p;
            while (l + 1 < r){
                int m = l + r >> 1;
                if (p == query(m, p)) l = m;
                else r = m;
            }
            std::cout << "! " << l << "\n";
        }else {
            l = p, r = n;
            while (l + 1 < r){
                int m = l + r >> 1;
                if (p == query(p, m)) r = m;
                else l = m;
            }
            std::cout << "! " << r << "\n";
        }
    }

D. Max Median

题目大意

Give you an array \(a\) of length \(n\). Find a subarray \(a[l\cdots r]\) with length at least \(k\) with the largest median. Note: $n\le 2\cdot10^5 $

思路

比赛的时候猜了个结论为直接使用长度为\(k\)的滑动窗口,用multiset维护,遗憾的是猜错了。

实际上有过一闪而过的想法,利用二分法解决问题,但是苦于无法找到\(\mathcal{O(n)}\)内可以完成任务的check函数。

本题中的中位数可以理解为:在一段序列中有超过一半的数大于等于该中位数。本题的官方题解给的是利用前缀和快速求解。

分为三步:

  • 给定中位数median,替换原序列,当元素大于median时为1否则为-1
  • 求出前缀和数组sum和最小前缀和数组mpre。因为,序列中位数大于等于median等价于该序列和前缀和的值大于0.
  • 由于序列长度至少为k,因此可以利用sum[i] - mpre[i - k] >= 1判断以i为结尾,长度至少为k序列的最大前缀和是否大于 0

最为精彩的就是将中位数转化为前缀和并进行替换。

代码

💎问题D代码💎

int n, k;
vt f;
inline bool check(int p){
    vt a(n + 1), sum(n + 1), mpre(n + 1);
    for (int i = 1; i <= n; ++ i) a[i] = (f[i - 1] >= p ? 1 : -1);
    for (int i = 1; i <= n; ++ i){
        sum[i] = sum[i - 1] + a[i];
        mpre[i] = min(mpre[i - 1], sum[i]);
    }
    int ok = 0;
    for (int i = k; i <= n; ++ i) if (sum[i] - mpre[i - k] >= 1) ok = 1;
    return ok;
}
void solve(){
    std::cin >> n >> k;
    f.resize(n);
    for (int i = 0; i < n; ++ i) std::cin >> f[i];
    int l = 1, r = 2e5 + 50;
    while (l + 1 < r){
        int m = l + r >> 1;
        if (check(m)) l = m;
        else r = m;
    }
    std::cout << l << "\n";
}
posted @ 2021-02-19 18:05  Last_Whisper  阅读(153)  评论(0编辑  收藏  举报