Codeforces Round #590 (Div. 3)

本文解析了六道编程挑战题目,包括价格均衡、社交网络模拟、水管连接问题、字符查询、特殊排列及字符串反转等,提供了详细的思路与代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. Equalize Prices Again

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T, N;
int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> T;
    while (T--) {
        cin >> N;
        ll sum = 0;
        for (int i = 1; i <= N; i++) {
            int x; cin >> x;
            sum += x;
        }
        ll p = sum / N;
        if (p * N < sum) p++;
        cout << p << endl;
    }
    return 0;
}

B.Social Network

题解:
模拟题,因为可以离线处理,所以预先将 i d i id_i idi给读入然后离散化处理即可
代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long	ll;
typedef unsigned long long	ull;
typedef pair<int, int>	pii;
const int MAX = 2e5 + 10;

int N, K;
int id[MAX], q[MAX], now[MAX];
int b[MAX], cnt;

int pos(int x) {
    return lower_bound(b + 1, b + 1 + cnt, x) - b;
}

int main() {
#ifdef ACM_LOCAL
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
    auto start_clock = clock();
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> N >> K;
    for (int i = 1; i <= N; i++)
        cin >> id[i], b[++cnt] = id[i];
    sort(b + 1, b + 1 + cnt);
    cnt = unique(b + 1, b + 1 + cnt) - b - 1;

    int head = 1, tail = 0;

    for (int i = 1; i <= N; i++) {//模拟
        int p = pos(id[i]);
        if (now[p]) continue;//如果已经在里面就跳过
        while (tail - head + 1 >= K) now[q[head]] = 0, head++;//弹出最上面的
        q[++tail] = p, now[p] = 1;
    }

    cout << tail - head + 1 << endl;
    for (int i = tail; i >= head; i--) {
        if (i != tail) cout << " ";
        cout << b[q[i]];
    }



#ifdef ACM_LOCAL
    cerr << (double)(clock() - start_clock) / CLOCKS_PER_SEC << "s" << endl;
#endif
    return 0;
}

C.Pipes

题解:
因为管子可以旋转,所以实质上只有两种管子,一种是1、2,一种是3、4、5、6,不妨分别记为①和②
因为第一种管子只能连通左右,而第二种管子可以连通上下左右
所以考虑2种情况
如果当前列不是最后一列的话,并且前一行通过来的管子接到的是②,那么必须还要一个②
如果前一行管子接到的是①,那么直接往下一列走就是了
最后判断下是否能在最后一列接到出口
代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long			ll;
typedef unsigned long long	ull;
typedef pair<int, int>		pii;
const int MAX = 2e5 + 10;

int T, N;
char s[2][MAX];

int main() {
#ifdef ACM_LOCAL
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
    auto start_clock = clock();
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &N);
        scanf("%s%s", s[0] + 1, s[1] + 1);
        int pre = 0, flag = 0;//pre表示上一列是从第一行来还是第二行来
        for (int i = 1; i <= N; i++) {
            char now = s[pre][i], other = s[pre ^ 1][i];//now当前管子,other为当前列另外一个管子
            if (now == '1' || now == '2') {//如果是第一种管子,直接通往下一列
                if (i == N && pre == 1) flag = 1;//如果是最后一列判一下
                continue;
            }
            //第二种管子
            if (other == '1' || other == '2') break;//如果另外一个管子是第一种管子,则不可能连通
            pre ^= 1;//连到另外一行去了
            if (i == N && pre == 1) flag = 1;
        }
        printf("%s\n", flag ? "YES" : "NO");

    }

#ifdef ACM_LOCAL
    cerr << (double)(clock() - start_clock) / CLOCKS_PER_SEC << "s" << endl;
#endif
    return 0;
}

D.Distinct Characters Queries

题解:
因为只有26个字母,所以直接状态压缩掉,用一个数 n u m num num来表示状态,即二进制对应位01状态分别表示没有和有,然后就可以用线段树来做,复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
#define lc  u<<1
#define rc  u<<1|1
#define m   (l+r)/2
#define mid (t[u].l+t[u].r)/2
using namespace std;
typedef long long	ll;
typedef unsigned long long	ull;
typedef pair<int, int>	pii;
const int MAX = 1e5 + 10;

int Q, N;
char s[MAX];

int get_sum(int x) {//得到区间状压num后计算有几个1,即几种
    int ans = 0;
    while (x) ans += x % 2, x /= 2;
    return ans;
}

struct SegTree{
    int l, r, num;
} t[MAX << 2];

void push_up(int u) {
    t[u].num = t[lc].num | t[rc].num;
}

void build(int u, int l, int r) {
    t[u].l = l, t[u].r = r;
    if (l == r) {
        int val = s[l] - 'a';
        t[u].num = pow(2, val);
        return;
    }
    build(lc, l, m); build(rc, m + 1, r);
    push_up(u);
}

void update(int u, int p) {
    if (t[u].l == t[u].r) {
        int val = s[t[u].l] - 'a';
        t[u].num = pow(2, val);
        return;
    }
    if (p <= mid) update(lc, p);
    if (p > mid) update(rc, p);
    push_up(u);
}

int query(int u, int ql, int qr) {
    if (ql <= t[u].l && t[u].r <= qr) return t[u].num;
    int ans = 0;
    if (ql <= mid) ans |= query(lc, ql, qr);
    if (qr > mid) ans |= query(rc, ql, qr);
    return ans;
}

int main() {
#ifdef ACM_LOCAL
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
    auto start_clock = clock();
#endif
    scanf("%s%d", s + 1, &Q);
    N = strlen(s + 1);
    build(1, 1, N);
    while (Q--) {
        int op, l, r, p; char x[10];
        scanf("%d", &op);
        if (op == 1) {
            scanf("%d%s", &p, x);
            s[p] = x[0];
            update(1, p);
        }
        else {
            scanf("%d%d", &l, &r);
            cout << get_sum(query(1, l, r)) << endl;
        }
    }

#ifdef ACM_LOCAL
    cerr << (double)(clock() - start_clock) / CLOCKS_PER_SEC << "s" << endl;
#endif
    return 0;
}

E.Special Permutations

题解:
这里直接计算一下每次转移会对答案有什么影响,统计完后直接输出答案即可
对于 a = m i n ( x [ i ] , x [ i + 1 ] ) , b = m a x ( x [ i ] , x [ i + 1 ] ) a=min(x[i],x[i+1]),b=max(x[i],x[i+1]) a=min(x[i],x[i+1]),b=max(x[i],x[i+1]),只需要考虑 a ! = b a!=b a!=b的情况( a = b a=b a=b的话怎么放都答案都是0)
如果是初始状态,即 1 , 2 , 3 , 4 , ⋅ ⋅ ⋅ , n 1,2,3,4,···,n 1,2,3,4,,n,那么当前答案显然就是 b − a b-a ba
因为 i i i不同序列也不同,这里我们对 p i p_i pi进行分类讨论
如果 i < a i<a i<a,则 a a a-> a + 1 a+1 a+1 b b b-> b + 1 b+1 b+1,答案仍然为 b − a b-a ba
如果 i = a i=a i=a,则答案为 b − 1 b-1 b1,变化量为 ( b − 1 ) − ( b − a ) = a + 1 (b-1)-(b-a)=a+1 (b1)(ba)=a+1
如果 a < i < b a<i<b a<i<b,则答案为 b − a − 1 b-a-1 ba1,变化量为 − 1 -1 1
如果 i = b i=b i=b,则答案为 a a a,变化量为 2 a − b 2a-b 2ab
如果 i > b i>b i>b,答案仍然为 b − a b-a ba
所以我们这里多用一个差分数列来统计即可(差分数列来计算 a < i < b a<i<b a<i<b的情况)

代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long			ll;
typedef unsigned long long	ull;
typedef pair<int, int>		pii;
const int MAX = 2e5 + 10;
 
int N, M;
ll x[MAX], d[MAX], cnt[MAX];
 
int main() {
#ifdef ACM_LOCAL
    freopen("input.in", "r", stdin);
    freopen("output.out", "w", stdout);
    auto start_clock = clock();
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> N >> M;
    ll ans = 0;
    for (int i = 1; i <= M; i++) {
        cin >> x[i];
        if (i != 1) {
            ll a = min(x[i - 1], x[i]), b = max(x[i - 1], x[i]);
            ans += b - a;//初始答案
            if (a + 1 <= b - 1) d[a + 1]--, d[b]++;//差分数列
            if (a < b) cnt[a] += a - 1, cnt[b] += 2 * a - b;//直接加到统计量上
        }
    }
    for (int i = 1; i <= N; i++) {
        d[i] += d[i - 1], cnt[i] += d[i];
        cout << ans + cnt[i] << endl;
    }
 
#ifdef ACM_LOCAL
    cerr << (double)(clock() - start_clock) / CLOCKS_PER_SEC << "s" << endl;
#endif
    return 0;
}

F.Yet Another Substring Reverse

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值