Codeforces Global Round 7

传送门

A. Bad Ugly Numbers

233333。

Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/3/19 22:36:37
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A>
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;

void run() {
    int n; cin >> n;
    if(n == 1) cout << -1 << '\n';
    else {
        cout << 2;
        for(int i = 1; i < n; i++) cout << 3;
        cout << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

B. Maximums

从前往后依次搞即可。

Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/3/19 22:39:26
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A>
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e5 + 5;

int n;
ll a[N], b[N];

void run() {
    ll Max = 0;
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> b[i];
    for(int i = 1; i <= n; i++) {
        a[i] = b[i] + Max;
        Max = max(Max, a[i]);
        cout << a[i] << " \n"[i == n];
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

C. Permutation Partitions

乘法原理运用。

Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/3/19 22:44:51
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A>
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e5 + 5, MOD = 998244353;

int n, k;
pii a[N];

void run() {
    cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i].fi, a[i].se = i;
    sort(a + 1, a + n + 1);
    ll ans = 0;
    vector <int> pos;
    for(int i = n - k + 1; i <= n; i++) ans += a[i].fi, pos.push_back(a[i].se);
    sort(all(pos));
    int ans2 = 1;
    for(int i = 1; i < sz(pos); i++) {
        ans2 = 1ll * ans2 * (pos[i] - pos[i - 1]) % MOD;
    }
    cout << ans << ' ' << ans2 << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

D2. Prefix-Suffix Palindrome (Hard version)

题意:
给出一个字符串\(s\)。
现在要找到一个最长的串\(t\),满足:

  • \(t\)为一个回文串;
  • \(t=pre_s+suf_s\),即是\(s\)串不重叠的前缀和后缀的拼接。

思路:
可以注意到若\(s\)串首尾字符相同,那么我们可以直接去除不影响答案。
简要证明:

  • 如果最后会去除一段前缀和一段后缀,那么我们一开始去掉不会影响答案,这种情况不用考虑。
  • 此时我们只会去除一段前缀/后缀。我们假设首位都去除了\(x\)个字符,现在\(s'\)串首尾不相等,即我们此时不可能从\(s'\)中选取前缀/后缀来形成回文串。不妨我们现在找到一个长度最大的前缀/后缀,其长度为\(len\),那么答案为\(len+x\);若不去除首尾\(x\)个字符,最大长度也为\(len+x\)。

那么直接贪心去掉前后相等的字符即可。
现在我们只需要找到长度最大的前缀/后缀为回文串就行。
可以马拉车或者回文自动机来搞,时间复杂度\(O(n)\)。
马拉车代码如下:

Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/3/19 23:11:34
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
//#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A>
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e6 + 5;

char s[N], t[N];

struct Manacher{
    char ch[N << 1];
    int p[N << 1];
    void work(char *s) {
        int l = 0;
        ch[l++] = '&'; ch[l++] = '#';
        for(int i = 0; s[i]; i++) {
            ch[l++] = s[i];
            ch[l++] = '#';
        }
        ch[l] = '\0';
        int mx = 0, id = 0;
        for(int i = 0; i < l; i++) {
            p[i] = i < mx ? min(p[2 * id - i], mx - i) : 1;
            while(ch[i + p[i]] == ch[i - p[i]]) p[i]++;
            if(i + p[i] > mx) mx = i + p[i], id = i;
        }
    }
    bool chk(int l, int r) {
        int mid = (l * 2 + r * 2) >> 1;
        return p[mid] - 1 >= r - l + 1;
    }
}Man;

void run() {
    cin >> (s + 1);
    int n = strlen(s + 1);
    int l = 1, r = n;
    while(l <= r && s[l] == s[r]) ++l, --r;
    if(l > r) {
        cout << (s + 1) << '\n';
        return;
    }
    for(int i = l; i <= r; i++) t[i - l + 1] = s[i];
    t[r - l + 2] = '\0';
    Man.work(t + 1);
    int res = 0;
    pii seg;
    dbg(t + 1, Man.chk(1, 3));
    for(int i = l; i <= r; i++) {
        if(Man.chk(1, i - l + 1)) {
            if(i - l + 1 > res) {
                res = i - l + 1;
                seg = MP(l, i);
            }
        }
        if(Man.chk(i - l + 1, r - l + 1)) {
            if(r - i + 1 > res) {
                res = r - i + 1;
                seg = MP(i, r);
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        if(i < l || i > r || (i >= seg.fi && i <= seg.se)) {
            cout << s[i];
        }
    }
    cout << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

E. Bombs

题意:
给出一个\(1...n\)的排列\(p_i\),给出一个序列\(q_i\),表示\(q_i\)位置上面的数会成为一个炸弹。
现在定义排列的“工作”:

  • 依次添加\(p_1,...,p_n\)到空集\(S\)中;
  • 若当前\(i\)位置为一个炸弹,那么会从集合\(S\)中取出一个最大的数。

现在回答对于每个\(i,1\leq i\leq n,q_1,q_2,\cdots,q_{i-1}\)都成为炸弹后,排列“工作”过后剩下的最大值是多少。

思路:

  • 显然最后的答案具有单调不增性。
  • 考虑从大到小进行枚举答案,那么我们只需要\(check\)当前答案是否合法即可。
  • 假设当前答案为\(x\),那么满足当前答案不合法的充要条件为:假设当前不小于\(x\)的数的位置从小到大依次为\(pos_1,\cdots,pos_k\),那么至少有\(t\)个炸弹位置不小于\(pos_{k-t+1}\)。
  • 那么我们维护一个\(b_i\),表示\(i...n\)这段后缀中,不小于\(x\)的数的个数减去这段中炸弹的个数。那么可以将上述充要条件修改为:对于所有大于等于\(x\)的位置,都有\(b_i\leq 0\);这一条件可以弱化为:对于所有位置,都有\(b_i\leq 0\)。
  • 因为我们维护的是两个数的差,当答案减小或者插入炸弹时,都只会影响一个前缀或者后缀,所以利用线段树维护一下就行。

挺有难度的一个题,如果想到了第三点那么之后应该就比较好想了,考场上就一直在思考有没有什么比较简单的方法来\(check\)。但其实第三点的思路就是很简单的贪心。
貌似还有\(O(n)\)的做法,知道了过后再来补(咕咕咕)

Code

/*
 * Author:  heyuhhh
 * Created Time:  2020/3/20 10:13:26
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
  template <template<typename...> class T, typename t, typename... A>
  void err(const T <t> &arg, const A&... args) {
  for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
  #define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 3e5 + 5;

int n;
int p[N], q[N], pos[N];

int maxv[N << 2], lz[N << 2];

void tag(int o, int l, int r, ll v) {
    maxv[o] += v;
    lz[o] += v;
}

void push_up(int o) {
    maxv[o] = max(maxv[o << 1], maxv[o << 1|1]);
}

void push_down(int o, int l, int r) {
    if(lz[o] != 0) {
        int mid = (l + r) >> 1;
        tag(o << 1, l, mid, lz[o]);
        tag(o << 1|1, mid + 1, r, lz[o]);
        lz[o] = 0;
    }
}

void update(int o, int l, int r, int L, int R, ll v) {
    if(L <= l && r <= R) {
        tag(o, l, r, v);
        return;
    }
    push_down(o, l, r);
    int mid = (l + r) >> 1;
    if(L <= mid) update(o << 1, l, mid, L, R, v);
    if(R > mid) update(o << 1|1, mid + 1, r, L, R, v);
    push_up(o);
}

void run() {
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> p[i], pos[p[i]] = i;
    for(int i = 1; i <= n; i++) cin >> q[i];
    int k = n;
    cout << k << ' ';
    update(1, 1, n, 1, pos[k], 1);
    for(int i = 1; i < n; i++) {
        update(1, 1, n, 1, q[i], -1);
        while(1) {
            int Max = maxv[1];
            if(Max <= 0) {
                update(1, 1, n, 1, pos[--k], 1);
            } else break;
        }
        cout << k << ' ';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

原文地址:https://www.cnblogs.com/heyuhhh/p/12530808.html

时间: 2024-08-30 08:23:17

Codeforces Global Round 7的相关文章

Codeforces Global Round 1 (A-E题解)

Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^(k-1)+a2*b^(k-2)+...+ak*b^0的奇偶性. 题解: 暴力求模2意义下的值就好了. 代码如下: #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; int

【手抖康复训练1 】Codeforces Global Round 6

[手抖康复训练1 ]Codeforces Global Round 6 总结:不想复习随意打的一场,比赛开始就是熟悉的N分钟进不去时间,2333,太久没写题的后果就是:A 题手抖过不了样例 B题秒出思路手抖过不了样例,C题秒出思路手抖过不了样例*3 D题 手抖 过的了样例 ,调了1h,赛后发现变量名写错了,改一个字符就能AC... 题目等补完题一起放上来QAQ 原文地址:https://www.cnblogs.com/ttttttttrx/p/12110199.html

Frets On Fire --- 2019 Codeforces Global Round 2 Problem D

原题:https://codeforces.com/contest/1119/problem/D 题意大概是一个n行1e18列的矩阵,其中每行第一个数为s[i],剩下的数每行依次以1的速度递增.就是说,矩阵元素 a[i][j] = s[i] + j .有q个询问,每个询问有两个参数l,r,求矩阵第l列到第r列(所有行)一共出现了几个不同的数. 这道题首先要先想到,两个参数 [l,r] 其实等价于一个参数 [0,r-l] ,也就是说矩阵第0~r-l行出现的数字的个数其实和第l-r行出现的个数是一样

[Codeforces]Codeforces Global Round 1

A - Parity 题意 给定一个$b$进制数,要求输出它在十进制下是奇数还是偶数. 分析 花了我略多的时间,首先题目中给的数字范围很大,不能直接转化为10进制. 分析性质,发现只有奇数乘奇数还是奇数,其他都是偶数. 对奇数进制和偶数进制分类讨论. 偶数进制看最低位的奇偶性,如果是奇数那么这个数就是奇数,不然是偶数. 奇数进制看每一位上奇数的个数,如果是奇数个奇数就是奇数,不然是偶数. 代码 1 #include <bits/stdc++.h> 2 using namespace std;

【 Codeforces Global Round 1 B】Tape

[链接] 我是链接,点我呀:) [题意] x轴上有m个连续的点,从1标号到m. 其中有n个点是特殊点. 让你用k段区间将这n个点覆盖. 要求区间的总长度最小. [题解] 一开始假设我们需要n个胶带(即包含每一个点) 然后因为k<=n 所以可能胶带不够用. 那么就得一个胶带跨过两个点. 怎么选择最好呢? 可以把b[i]-b[i-1]-1处理出来排个序. (优先取较小的花费) 然后取前n-k个累加和sum. 因为每取一个就少用一段胶带. 然后sum+n就是答案了 [代码] import java.i

【Codeforces Global Round 1 C】Meaningless Operations

[链接] 我是链接,点我呀:) [题意] 给你一个a 让你从1..a-1的范围中选择一个b 使得gcd(a^b,a&b)的值最大 [题解] 显然如果a的二进制中有0的话. 那么我们就让选择的b的二进制中对应的位置为1 剩下全为0就好 这样a的二进制全都变成1之后就是答案了(gcd的右边是0). 但是如果a的二进制里面全是1的话. 就没办法这么构造了 这里有两种情况. ①.1的个数是偶数 那么就101010这样构造 另外一个数就是010101 答案就是010101转换成十进制 ②.1的个数是奇数

Codeforces Global Round 1

A. Parity 签. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int b, k, a[N]; 6 7 int main() 8 { 9 while (scanf("%d%d", &b, &k) != EOF) 10 { 11 int res = 0; 12 for (int i = 1; i <= k; ++i) scanf("%d&

【Codeforces Global Round 1 A】Parity

[链接] 我是链接,点我呀:) [题意] 给你一个k位数b进制的进制转换. 让你求出来转成10进制之后这个数字是奇数还是偶数 [题解] 模拟一下转换的过程,加乘的时候都记得对2取余就好 [代码] import java.io.*; import java.util.*; public class Main { static int N = (int)1e5; static InputReader in; static PrintWriter out; static int b,k; static

[codeforces]Codeforces Global Round 1 F. Nearest Leaf

题解:  语文题????  上面说的一段代码 告诉你的是  节点编号顺序与dfs序顺序一致  也就是你  dfs序以后编号就是[1,n]  根据这个特性  那么我们只需要维护每个叶子节点到查询v的距离即可  那么我们只需要离线所有查询 然后对子树修改即可   用线段树来维护区间加和区间最小值就行 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #inc

Codeforces Global Round 1 自闭记

A:签到. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long char getc(){char c=getchar();while ((c<'A'||c>'Z')&&a