Educational Codeforces Round 102 (Rated for Div. 2)

Educational Codeforces Round 102 (Rated for Div. 2)

前言

我是傻逼

A.Replacing Elements

先判一下a中最大元素是否<=d 如果否 再判一下最小的两个元素之和是否<=d就行了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 107;
int n, m, q, k, t, d, a[maxn], flag;
int main() {
    cin >> t;
    while (t--) {
        flag = 0;
        cin >> n >> d;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            if (a[i] > d) flag = 1;
        }
        if (flag == 0) {
            puts("YES");
            continue;
        }
        sort(a + 1, a + n + 1);
        if (a[1] + a[2] <= d) puts("YES");
        else puts("NO");
    }
}

B.String LCM

我是傻逼 暴力调一个半小时
直接求出字符串的循环节 如果两个字符串循环节不一样无解
然后输出长度为lcm(n,m) 循环节相同的字符串就行了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 27;
int n, m, q, k, flag, sa, ta, sb, tb;
string s, t;
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
int main() {
    cin >> q;
    while (q--) {
        flag = sa = sb = ta = tb = 0;
        cin >> s >> t;
        //特判单字母的情况
        n = s.length(); m = t.length();
        if (n < m) { 
            swap(s, t);
            swap(n, m);
        }
        for (int l = 1; l <= m; l++)  {
            if (n % l || m % l) continue;
            int i = 0;
            for (i = 0; i < n; i++) {
                if (s[i] != s[i % l]) break;
            }
            if (i == n) {
                for (int j = 0; j < m; j++) {
                    if (s[j] != t[j]) {flag = 0;    goto gg;};
                }
                for (int k = 0; k < n*m/gcd(n, m); k++) {
                    putchar(s[k%l]);
                }
                putchar('\n');
                flag = 1;
                break;
            } 
            if (flag == 1) break;
        }
        gg:
        if (!flag) puts("-1");
    }
    return 0;
}

C.No More Inversions

可以暴力出小范围的数据来找找规律 比手玩高效(废话
a是固定的 为1 2 3 … k-(n-k) … k-1 k k-1 k-2 … k-(n-k)
逆序对一共有 ( n − k ) 2 = 1 + 3 + 5 + 7 + . . . + ( n − k ) (n-k)^2 = 1 + 3 + 5 + 7 + ... + (n-k) (nk)2=1+3+5+7+...+(nk)个 全是下标k-(n-k)之后的数贡献的
那么b就是 p [ 1 ] p [ 2 ] p [ 3 ] . . . . p [ k − ( n − k ) ] . . . p [ k − 1 ] p [ k ] p [ k − 1 ] . . . . p [ k − ( n − k ) ] p[1] p[2] p[3] .... p[k-(n-k)] ... p[k-1] p[k] p[k-1] .... p[k-(n-k)] p[1]p[2]p[3]....p[k(nk)]...p[k1]p[k]p[k1]....p[k(nk)]
从下标为k-(n-k)的位置开始到b数组结束 这一段是对称的

对于形如 s 1 , s 2 , . . . , s k − 1 , s k , s k − 1 , . . . , s 1 s_1,s_2,...,s_{k-1},s_{k},s_{k-1},...,s_{1} s1,s2,...,sk1,sk,sk1,...,s1的序列 如果 s i s_i si互不相同 那么s的逆序对数固定,均为 ( k − 1 ) 2 (k-1)^2 (k1)2

s i s_i si按权值分组,每次取出任意两组,假设他们的值分别是x和y,形成的序列一定都是 . . . x . . . y . . . x . . . ...x...y...x... ...x...y...x...或者是 x . . . y . . . y . . . x . . x...y...y...x.. x...y...y...x..结构的,这两种结构分别贡献一个和两个逆序对
所以一共有 C k − 1 2 + k − 1 = ( k − 1 ) 2 C_{k-1}^2+k-1=(k-1)^2 Ck12+k1=(k1)2对逆序对
所以b中的逆序对也全部来自对称的那一段
所以b前面只能顺序放1 2 3… k-(n-k)-1.
后面要字典序最大 只能把k放最前面了
所以p[k-(n-k)] == k,其之后的p递减
p前面从1开始递增

#include<bits/stdc++.h>
using namespace std;
int t, n, k;
int main() {
    cin >> t;
    while (t--) {
        cin >> n >> k;
        for (int i = 1; i < (2*k-n); i++) printf("%d ", i);
        for (int i = k; i >= 2*k-n; i--)  printf("%d ", i);
        printf("\n");
    }
}

D.Program

n个操作,m次询问
每次操作把x加一或者减一,求如果去掉第[l,r]次操作,剩下的操作过程中x会变成多少个不同的数
n,m<=2e5
注意到x的取值是连续的 所以求出区间最大值和最小值减一下就是答案

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
#define ls p << 1
#define rs p << 1 | 1
struct _ {
    int l, r, ans;
}e[maxn];
int t, n, m, a[maxn], mx[maxn << 2], mi[maxn << 2];
void build(int p, int l, int r) {
    if (l == r) {mx[p] = mi[p] = a[l]; return;}
    int mid = l + r >> 1;
    build(ls, l, mid); build(rs, mid + 1, r);
    mx[p] = max(mx[ls], mx[rs]);
    mi[p] = min(mi[ls], mi[rs]);
}
int querymx(int p, int l, int r, int x, int y) {
    if (x <= l && r <= y) {
        return mx[p];
    }
    int mid = l + r >> 1, res = -999999;
    if (x <= mid) res = max(res, querymx(ls, l, mid, x, y));
    if (y > mid) res = max(res, querymx(rs, mid + 1, r, x, y));
    return res;
}
int querymi(int p, int l, int r, int x, int y) {
    if (x <= l && r <= y) return mi[p];
    int mid = l + r >> 1, res = 999999;
    if (x <= mid) res = min(res, querymi(ls, l, mid, x, y));
    if (y > mid) res = min(res, querymi(rs, mid+1, r, x, y));
    return res;
}
int rd() {
    int x;
    scanf("%d", &x);
    return x;
}
char s[maxn];

int main() {
    t = rd();
    while (t--) {
        n = rd(), m = rd();
        scanf("%s", s + 1);
        int x = 0;
        for (int i = 1; i <= n; i++) {
            if (s[i] == '+') x++;
            else x--;
            a[i] = x;
        }
        build(1, 1, n);
        for (int i = 1; i <= m; i++) {
            e[i].l = rd(); e[i].r = rd();
            int Mx = 0, Mi = 0, M1, M2, M3, m1, m2, m3;
            if (e[i].l > 1) {
                M1 = querymx(1, 1, n, 1, e[i].l - 1);
                m1 = querymi(1, 1, n, 1, e[i].l - 1);
            } else M1 = -999999, m1 = 999999;
            if (e[i].r < n) {
                M2 = querymx(1, 1, n, e[i].r+1, n) - a[e[i].r] + a[e[i].l - 1];
                m2 = querymi(1, 1, n, e[i].r+1, n) - a[e[i].r] + a[e[i].l - 1];
            } else M2 = -999999, m2 = 999999;
            Mx = max(Mx, max(M1, M2));
            Mi = min(Mi, min(m1, m2));
            e[i].ans = Mx - Mi + 1;
            //printf("Mx == %d Mi == %d\n", Mx, Mi);
        }
        for (int i = 1; i <= m; i++) {
            printf("%d\n", e[i].ans);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值