Educational Codeforces Round 102 (Rated for Div. 2)部分题解(A,B,C,D)

jusge: CodeForces

题解的分析顺序采用倒叙。

D. Program

judge: CodeForces

题意

给你一个初始值为 0 0 0 x x x,和由若干个+-组成的序列,+代表下一轮 x x x 的值+1,-代表下一轮 x x x 的值-1。

m m m 次操作,每次操作给出一段区间 [ l , r ] [l,r] [l,r],求出忽略 [ l , r ] [l,r] [l,r] 区间的序列执行过程中 x x x 的不同状态的数量。

例如当序列为--+时, x x x 的取值是0,-1,-2,-1,一共有 3 3 3 种状态。

题解

当一段操作确定时,求出状态数并不难。只需要找出所有状态的最大值减去最小值再加一即可。

问题在于当忽略中间的某一段操作时,后面的状态就不确定了。

定义 x [ 0 ] = 0 x[0]=0 x[0]=0,代表初始状态, x [ 1 ] x[1] x[1] 为第一个操作完成后的 x x x 的状态,剩下的依次递推。

维护 x x x 上的区间最大值和最小值,当忽略区间为 [ l , r ] [l,r] [l,r] 的操作时(为了简化,我们假设 l > 1 l>1 l>1 r < n r<n r<n),求出 [ 0 , l − 1 ] [0,l-1] [0,l1] 的最大值,最小值分别为 l m a , l m i lma,lmi lma,lmi [ r , n ] [r,n] [r,n]的最大值,最小值分别为 r m a , r m i rma,rmi rma,rmi。注意所求的最值的区间需要包含它的前一个状态,因为状态数计数时是考虑 x x x 的前一个状态的,所以计算的区间分别是从 0 0 0 r r r 开始,而不是 1 1 1 r + 1 r+1 r+1

由于中间忽略了一部分操作,后面计算得来的状态的最值不可信。要保持状态同步需要让

r m a = r m a − x [ r ] + x [ l − 1 ] rma=rma-x[r]+x[l-1] rma=rmax[r]+x[l1]

r m i = r m i − x [ r ] + x [ l − 1 ] rmi=rmi-x[r]+x[l-1] rmi=rmix[r]+x[l1]

这样就求出全部操作的执行过程中 x x x 的最大值和最小值了。

那么 x x x 的不同状态的数量无非就是 l m a − l m i + 1 lma-lmi+1 lmalmi+1, l m a − r m i + 1 lma-rmi+1 lmarmi+1, r m a − r m i + 1 rma-rmi+1 rmarmi+1, r m a − l m i + 1 rma-lmi+1 rmalmi+1中的最大值。

考虑到线段树维护的区间是从 1 1 1 开始的,所以我们把维护的区间整体右移一位,也就是定义 x [ 1 ] = 0 x[1]=0 x[1]=0,代表初始值, x [ 2 ] x[2] x[2] 为第一个操作完成后的 x x x 的状态,剩下的以此递推。

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
// #define max(a, b) ((a) > (b) ? (a) : (b))
// #define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 200005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;

inline int read() {
    
    
    int x(0), f(1); char ch(getchar());
    while (ch<'0' || ch>'9') {
    
     if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') {
    
     x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

struct poi {
    
    

};

int n, m;
char s[maxn];
int a[maxn];

int ma[maxn << 2], mi[maxn << 2];
void build(LL node, LL beg, LL end) {
    
    
    if (beg == end) {
    
    
        ma[node] = a[beg];
        mi[node] = a[beg];
        return;
    }
    LL mid = (beg + end) >> 1;
    build(node << 1, beg, mid);
    build(node << 1 | 1, mid + 1, end);
    ma[node] = max(ma[node << 1], ma[node << 1 | 1]);
    mi[node] = min(mi[node << 1], mi[node << 1 | 1]);
}
LL queryMax(LL node, LL beg, LL end, LL l, LL r) {
    
    
    if (l <= beg && r >= end) return ma[node];
    LL ans = -inf;
    LL mid = (beg + end) >> 1;
    if(mid >= l) ans = max(ans, queryMax(node << 1, beg, mid, l, r));
    if(mid < r) ans = max(ans, queryMax(node << 1 | 1, mid + 1, end, l, r));
    return ans;
}
LL queryMin(LL node, LL beg, LL end, LL l, LL r) {
    
    
    if (l <= beg && r >= end) return mi[node];
    LL ans = inf;
    LL mid = (beg + end) >> 1;
    if(mid >= l) ans = min(ans, queryMin(node << 1, beg, mid, l, r));
    if(mid < r) ans = min(ans, queryMin(node << 1 | 1, mid + 1, end, l, r));
    return ans;
}

void init() {
    
    

}

void sol() {
    
    
    init();
    scanf("%s", s + 1);
    int x = 0;
    _rep(i, 1, n) {
    
    
        if(s[i] == '-') a[i + 1] = --x;
        else a[i + 1] = ++x;
    }
    build(1, 1, n + 1);
    _for(i, m) {
    
    
        int ans = 1;
        int l = read(), r = read();
        l = max(1, l);
        r = min(r, n);
        if(l > 1 && r < n) {
    
    
            int lma = queryMax(1, 1, n + 1, 1, l);
            int lmi = queryMin(1, 1, n + 1, 1, l);
            int rma = queryMax(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
            int rmi = queryMin(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
            ans = max(ans, lma - lmi + 1);
            ans = max(ans, rma - rmi + 1);
            ans = max(ans, lma - rmi + 1);
            ans = max(ans, rma - lmi + 1);
        }
        else if(l > 1) {
    
    
            int lma = queryMax(1, 1, n + 1, 1, l);
            int lmi = queryMin(1, 1, n + 1, 1, l);
            ans = max(ans, lma - lmi + 1);
        }
        else if(r < n) {
    
    
            int rma = queryMax(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
            int rmi = queryMin(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
            ans = max(ans, rma - rmi + 1);
        }
        printf("%d\n", ans);
    }
}

int main() {
    
    
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    // debug = 1;
#endif
    time_t beg, end;
    if(debug) beg = clock();

    int T = read();
    _for(i, T) {
    
    
        n = read(), m = read();
        sol();
    }

    if(debug) {
    
    
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    return 0;
}

C. No More Inversions

judge: CodeForces

题意

给你两个整数 n n n k k k,可以唯一确定一个序列a:

1,2,3,…,k−1,k,k−1,k−2,…,k−(n−k) ( k ≤ n < 2 k ) (k≤n<2k) (kn<2k)

让你找出一个排列 p p p,并且序列 b [ i ] = p [ a [ i ] ] b[i]=p[a[i]] b[i]=p[a[i]],使 b b b 的逆序数不大于 a a a 的逆序数,且 b b b 的字典序最大

题解

找规律发现,当我们交换 p p p [ 2 k − n , k ] [2k-n,k] [2kn,k] 中的两个数字时,逆序数不变。

例如1 2 3 2的逆序数为 1 1 1,交换 2 2 2 3 3 3 后序列变成1 3 2 3,逆序数依然是 1 1 1.

再比如1 2 3 4 3 2的逆序数为 4 4 4,交换 2 2 2 4 4 4 后序列变成1 4 3 2 3 4,逆序数依然是 4 4 4

要使字典序最大,需要把较大的数尽可能移到前面,所以我们使序列变成 1,2,...,2k-n,k,k-1,...,2k-n+1,2k-n,2k-n+1,...,k-1,k ( k ≤ n < 2 k ) (k≤n<2k) (kn<2k)

例如1,2,3,4,5,4,3变成1,2,5,4,3,4,5

剩下的就是编码问题,这里不再赘述。

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 200005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;

inline int read() {
    
    
    int x(0), f(1); char ch(getchar());
    while (ch<'0' || ch>'9') {
    
     if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') {
    
     x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

struct poi {
    
    

};

int n, k;
int a[maxn];
int p[maxn];

void init() {
    
    

}

void sol() {
    
    
    init();
    n = read(), k = read();
    if(n == 1) {
    
    
        printf("1\n");
        return;
    }
    if(n == k) {
    
    
        _rep(i, 1, n) printf("%d%s", i, nl(i, n + 1));
        return;
    }
    _rep(i, 1, k) a[i] = i;
    _rep(i, 1, n - k) a[k + i] = k - i;
    _rep(i, 1, k) p[i] = i;
    for(int i = 1; i <= n - k + 1; ++i) p[2 * k - n + i - 1] = k - i + 1;
    _rep(i, 1, k) printf("%d%s", p[i], nl(i, k + 1));
}

int main() {
    
    
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    // debug = 1;
#endif
    time_t beg, end;
    if(debug) beg = clock();

    int T = read();
    _for(i, T) {
    
    
        sol();
    }

    if(debug) {
    
    
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    return 0;
}

B. String LCM

judge: CodeForces

题意

定义一种性质,如果有一个字符串 l l l,满足 l l l 是由若干次字符串 s s s 拼接而成,且满足 l l l 是由若干次 t t t 拼接而成,满足此条件的最短的 l l l 称为 s s s t t t 的“LCM”。

有两个字符串 s s s t t t,判断他们是否存在“LCM”,若存在就输出他们的“LCM”,否则输出-1

题解

定义 l s ls ls s s s 的长度, l t lt lt t t t 的长度。

由于“LCM”唯一,所以“LCM”的长度一定是 n = l s × l t × g c d ( l s , l t ) n=ls\times lt\times gcd(ls,lt) n=ls×lt×gcd(ls,lt)

重复 n / l s n/ls n/ls s s s 串,再将之与重复 n / l t n/lt n/lt 次的 t t t 串作比较,若完全相同则说明存在“LCM”,且“LCM”就是长度为 n n n 的串。否则就不存在“LCM”。

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 100005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;

inline int read() {
    
    
    int x(0), f(1); char ch(getchar());
    while (ch<'0' || ch>'9') {
    
     if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') {
    
     x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

struct poi {
    
    

};

char s[maxn], t[maxn], tar[maxn];

void init() {
    
    

}

int sol() {
    
    
    init();
    scanf("%s%s", s, t);
    int ls = strlen(s), lt = strlen(t);
    int n = ls / __gcd(ls, lt) * lt;
    _for(i, n / ls) _for(j, ls) tar[i * ls + j] = s[j];
    _for(i, n / lt) _for(j, lt) if(tar[i * lt + j] != t[j]) return -1;
    tar[n] = 0;
    printf("%s\n", tar);
    return 1;
}

int main() {
    
    
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    debug = 1;
#endif
    time_t beg, end;
    if(debug) beg = clock();

    int T = read();
    _for(i, T) {
    
    
        if(sol() == -1) printf("-1\n");
    }

    if(debug) {
    
    
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    return 0;
}

A. Replacing Elements

judge: CodeForces

题意

定义一种操作:选择三个不同的下标使得 a [ i ] = a [ j ] + a [ k ] a[i]=a[j]+a[k] a[i]=a[j]+a[k]

你可以执行此操作任意次。

回答是否可以通过若干次此操作使数列的任何一个数字都小于等于 m m m

题解

首先检查一下数列里是否有大于 m m m 的数字,如果没有那就什么都不用做就能满足要求。

其次检查最小的两个数的和是否小于等于 m m m。如果小于等于 m m m,那么我就可以把其余的所有数字都变成这两个数字的和,这样所有的数字就都小于等于 m m m 了。否则就是不可能使所有的数字都小于等于 m m m

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 100005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;

inline int read() {
    
    
    int x(0), f(1); char ch(getchar());
    while (ch<'0' || ch>'9') {
    
     if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') {
    
     x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

struct poi {
    
    

};

int a[maxn];

void init() {
    
    

}

void sol() {
    
    
    init();
    int n = read(), m = read();
    int mi = inf, sec = inf;
    int f = 1;
    _for(i, n) {
    
    
        a[i] = read();
        if(a[i] > m) f = 0;
    }    
    if(f) {
    
    
        printf("YES\n");
        return;
    }
    _for(i, n) {
    
    
        if(a[i] < mi) sec = mi, mi = a[i];
        else if(a[i] < sec) sec = a[i];
    }
    printf("%s\n", mi + sec <= m ? "YES":"NO");
}

int main() {
    
    
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    debug = 1;
#endif
    time_t beg, end;
    if(debug) beg = clock();

    int T = read();
    _for(i, T) {
    
    
        sol();
    }

    if(debug) {
    
    
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42856843/article/details/112665571
今日推荐