Codeforces Round #703 (Div. 2)

Codeforces Round #703 (Div. 2)

A. Shifting Stacks

题目大意

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

思路

能够贪心作,保证严格递增以后将多余的数所有传下去。c++

仔细研究得出结论,最优为\(\{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 .函数

思路

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

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

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

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

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

代码

💎问题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]\).get

思路

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

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

首先讨论最大值在左仍是在右,由于须要讨论端点状况。

代码

💎问题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"; } 
    

  
相关文章
相关标签/搜索