CFEducational Codeforces Round 66题解报告

CFEducational Codeforces Round 66题解报告

感觉丧失了唯一一次能在CF上超过wqy的机会QAQ

A

不管

B

不能直接累计乘法打\(tag\),要直接跳

C

考虑二分第\(k\)小的值

那么问题就变成了

每一个数变成了\([x-mid,x+mid]\)的一段区间,如果有一个位置被覆盖了超过\(k\)次

那么\(mid\)一定合法

类似括号匹配

每次碰到左端点就贡献+1

右端点就统计答案然后-1

维护答案的同时顺便维护位置就好了

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 4e5 + 3;
int a[N];
int n,k,ans;
vector <pii> G;
inline int read(){
    int v = 0,c = 1;char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') c = -1;
        ch = getchar();
    }
    while(isdigit(ch)){
        v = v * 10 + ch - 48;
        ch = getchar();
    }
    return v * c;
}
inline bool check(int mid){
    G.clear();
    for(int i = 1;i <= n;++i) G.push_back(mk(a[i] - mid,0)),G.push_back(mk(a[i] + mid,1));
    sort(G.begin(),G.end());
    int now = 0;
    for(int i = 0;i < (int)G.size();++i){
        if(G[i].se == 0) now++;
        else{
            if(now >= k){ans = G[i].fi;return 1;}
            now--;
        }
    }
    return 0;
}
int main(){
    int T = read();
    while(T--){
        n = read(),k = read() + 1;
        for(int i = 1;i <= n;++i) a[i] = read();
        int l = 0,r = 1e9;
        while(l <= r){
            int mid = (l + r) >> 1;
            if(check(mid)) r = mid - 1;
            else l = mid + 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

D

DP方法非常显然

但是时间复杂度不对

又没有凸性,无法优化(至少我不会)

只能考虑别的方法

发现每一次分段其实就是加上某一个后缀的值

很显然某个后缀只能加一次

所以题目变成了求\([2,n]\)的前\(k - 1\)大的后缀的和

最后将答案加上权值总和

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<LL,LL>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 5e5 + 3;
const LL INF = 1e15;
LL a[N];
LL sum[N];
LL maxx[N];
int n,k;
int tag[N];
priority_queue <pii> q;
inline int read(){
    int v = 0,c = 1;char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') c = -1;
        ch = getchar();
    }
    while(isdigit(ch)){
        v = v * 10 + ch - 48;
        ch = getchar();
    }
    return v * c;
}
int main(){

    n = read(),k = read();
    for(int i = 1;i <= n;++i) a[i] = read(),maxx[i] = -INF;
    maxx[n] = sum[n] = a[n];
    q.push(mk(sum[n],n));
    for(int i = n - 1;i >= 1;--i){
    //  cout << i << endl;
        sum[i] = sum[i + 1] + a[i];
        maxx[i] = max(maxx[i + 1],sum[i]);
        if(i != 1) q.push(mk(sum[i],i));
    }
    LL ans = sum[1];
    //cout << "GG" << endl;
    for(int i = 1;i < k;++i,q.pop()){
        ans += q.top().fi;
    }
    cout << ans;
    return 0;
}

F

方法一;考虑分治

题目中要求的区间转化一下就是下面两个条件

区间\([l,r]\)合法当且仅当

\(1\) 区间最大值为\(r - l + 1\)

\(2\) 区间无重复元素

我们考虑每次按照最大值去分治

考虑跨过最大值的贡献

接下来要满足第二个条件

我们设\(pre_i\)为\(a_i\)上一次出现的位置

\(max_i\)为\(pre_i\)的前缀max

发现区间\([l,r]\)无重复元素的意思是

\(max_r < l\)

就是每个数上一次出现的位置都在\(l\)左边

由于区间最大值就是区间长度

我们就可以通过枚举一边寻找另一边的方式求解

方法二;

我们给每一个数随机分配一个\(128\)位的数字

所以区间\([L,R]\)符合条件

就可以用前缀异或去表示

由于合法区间一定包含\(1\)

我们就从一个\(1\)开始到下一个\(1\)为止去寻找最大值在右边的贡献

之后把数组反过来再来一遍

这样\(1\)可能会被计算两边,特判就好。

原文地址:https://www.cnblogs.com/wyxdrqc/p/11385714.html

时间: 2024-10-08 20:43:40

CFEducational Codeforces Round 66题解报告的相关文章

Codeforces Round #541 题解

codeforces Round #541 C 题意 给你100个人,让你将它们围成一个圆,使得:"任意相邻的两人身高差的绝对值" 中的最大值 最小 题解 显然的构造方法:先排序,让所有人1 2 报数,报2的出列,排尾变排头接到报 1 的原队列后面 证明: 显然这样的构造方法保证身高差最大为 max{(a[i+2]-a[i]) }(i=1..n,环状,a[i]升序): 我们可以说明对于任意的i,身高差至少为(a[i+2]-a[i]), 如果我们将每个人看成一个点,相邻关系看成一条无向边

codeforces Round#332Div2 题解

codeforces Round#332Div2 AB 签到题 比较激动,纷纷WA了一发. C 把数组h复制给a,然后对a数组排序. 对h和a数组,求前缀和,有多少个位置满足\(\sum a[i] = \sum h[i]\), 就最多能分成多少块. D 我们枚举更短的那条边,这样的边不会太多. 然后求,更长的那条边. E 符合xxx限定条件的图的计数问题.数据范围很状压. 我们用dp[mask][root]表示,集合mask里的点,以root为根,不违背限定条件的方案数. 接下来考虑dp[mas

Codeforces Educational Codeforces Round 54 题解

题目链接:https://codeforc.es/contest/1076 A. Minimizing the String 题意:给出一个字符串,最多删掉一个字母,输出操作后字典序最小的字符串. 题解:若存在一个位置 i 满足 a[i] > a[i+1],若不删除 a[i] 则后续操作不可能更优. 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define ull unsigned

Codeforces Round #302 解题报告

感觉今天早上虽然没有睡醒但是效率还是挺高的... Pas和C++换着写... 544A. Set of Strings You are given a string q. A sequence of k strings s1, s2, ..., sk is called beautiful, if the concatenation of these strings is string q(formally, s1 + s2 + ... + sk = q) and the first chara

Codeforces Round #513解题报告(A~E)By cellur925

我是比赛地址 A:Phone Numbers $Description$:给你一串数字,问你能组成多少开头为8的11位电话号码. $Sol$:统计8的数量,与$n$%11作比较. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,len,cnt,ans; 8 char ch[1000]; 9 10 int main() 11 {

Educational Codeforces Round 55 题解

题解 CF1082A [Vasya and Book] 史上最难A题,没有之一 从题意可以看出,翻到目标页只有三种办法 先从\(x\)到\(1\),再从\(1\)到\(y\) 先从\(x\)到\(n\),再从\(n\)到\(y\) 直接从\(x\)到\(y\) 三种的必要条件分别是 \((y-1)\mod d \equiv 0\) \((n-y)\mod d \equiv 0\) \(|x-y|\mod d \equiv 0\) 所以如果上面三种都不满足的话就输出\(-1\) 不然就取最小的输出

Educational Codeforces Round 66 (Rated for Div. 2) A

A. From Hero to Zero 题目链接:http://codeforces.com/contest/1175/problem/A 题目 ou are given an integer n and an integer kIn one step you can do one of the following moves:decrease n by 1;divide n by k if n is divisible by k.For example, if n=27 and k=3 yo

Codeforces Round 596 题解

万幸的是终于碰上了一场上分好场. 不幸的是一开始差点不会 A. 万幸的是想了个不那么稳的结论过了 pretest. 不幸的是罚时很高,而且慌得一比. 万幸的是然后半个小时内把 B 和 C 码了. 不幸的是然后就只能看着排名一点一点掉了. 万幸的是最后 A 没被叉掉. 不幸的是我居然没敢去叉人. 万幸的是我就是叉了 10 个人排名也不会上涨超过 5. 不幸的是我每掉一名都会少涨两三分. 万幸的是我没去打隔壁的 ZR. 不幸的是我发现这场 ZR 我一题不会,打了就会掉分-- 2A 没仔细想,但是应该

Codeforces Round #616 题解

A题 我们注意到如果存在两个奇数,那么就能满足题目条件,所以我们就从头寻找两个奇数,没有的话就是无解 #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #include<string> #include<cstring> #include<map> using namespace st