Codeforces Round #590 (Div. 3)

A - Equalize Prices Again

题意:给n个商品,每个商品价格不同,要调整他们的价格,使得总价不下降且他们的价格相等,在此基础上最小化总价。

题解:找超过原总价的最小的n的倍数。

void test_case() {
    int n;
    scanf("%d", &n);
    ll sum = 0;
    for(int i = 1; i <= n; ++i) {
        ll tmp;
        scanf("%lld", &tmp);
        sum += tmp;
    }
    sum = (sum + n - 1) / n;
    printf("%lld
", sum);
}

B1 - Social Network (easy version)

见下

B2 - Social Network (hard version)

题意:有个手机,屏幕能显示k个聊天窗口,已知n个人给你发消息的序列,求最终的聊天窗口。

调整规则如下:

  1. 假如当前聊天窗口中有这个人,啥都不做,结束
  2. 否则,若窗口已满,去掉最底部的窗口
  3. 其他窗口下移,新的显示在顶部

题解:看起来就是个队列,然后还要查队列里有没有某个元素,这个用个set就完事了。不过最后题目要从顶部到底部输出,所以一开始就用双端队列就很方便。

set<int> s;
deque<int> q;
 
void test_case() {
    s.clear();
    int n, k;
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i) {
        int id;
        scanf("%d", &id);
 
        if(s.count(id))
            continue;
        else {
            if(q.size() >= k) {
                s.erase(q.front());
                q.pop_front();
            }
            q.push_back(id);
            s.insert(id);
        }
    }
    printf("%d
", (int)q.size());
    while(q.size()) {
        printf("%d ", q.back());
        q.pop_back();
    }
    printf("
");
}

C - Pipes

题意:有个两行的水管,水管只有两种形状,直的,或者拐角的。连接这些水管使得(1,0)的水可以流到(2,n+1)。

题解:由于只有两行,所以每行结束必须往右流,直接dp即可。注意设置的时候不要在同层之间传递。

char s[2][200005];
bool dp[2][200005];
 
void test_case() {
    int n;
    scanf("%d", &n);
    scanf("%s%s", s[0] + 1, s[1] + 1);
    for(int i = 1; i <= n; ++i)
        s[0][i] -= '0', s[1][i] -= '0';
    /*for(int i = 1; i <= n; ++i)
        putchar(s[0][i]);
    putchar('
');
    for(int i = 1; i <= n; ++i)
        putchar(s[1][i]);
    putchar('
');*/
    for(int i = 1; i <= n; ++i)
        dp[0][i] = dp[1][i] = 0;
    dp[0][0] = 1;
    dp[1][0] = 0;
    for(int i = 1; i <= n; ++i) {
        if(dp[0][i - 1] == 1 && s[0][i] <= 2)
            dp[0][i] = 1;
        if(dp[1][i - 1] == 1 && s[1][i] <= 2)
            dp[1][i] = 1;
        if(dp[0][i - 1] == 1 && s[0][i] >= 3 && s[1][i] >= 3)
            dp[1][i] = 1;
        if(dp[1][i - 1] == 1 && s[1][i] >= 3 && s[0][i] >= 3)
            dp[0][i] = 1;
    }
    /*for(int i = 0; i <= n; ++i)
        printf("%d", (int)dp[0][i]);
    putchar('
');
    for(int i = 0; i <= n; ++i)
        printf("%d", (int)dp[1][i]);
    putchar('
');*/
    if(dp[1][n])
        puts("YES");
    else
        puts("NO");
}

D - Distinct Characters Queries

题意:给个只有小写拉丁字母的字符串,然后q次操作。

操作1:把pos位置换成小写拉丁字母c。(pos一定在原串中)

操作2:求[l,r]区间有多少种字母。

题解:线段树

struct SegmentTree {
#define ls (o<<1)
#define rs (o<<1|1)
    static const int MAXN = 200000;
    int a[MAXN + 5];
    int st[(MAXN << 2) + 5];
 
    void PushUp(int o) {
        st[o] = st[ls] | st[rs];
    }
 
    void Build(int o, int l, int r) {
        if(l == r)
            st[o] = a[l];
        else {
            int m = l + r >> 1;
            Build(ls, l, m);
            Build(rs, m + 1, r);
            PushUp(o);
        }
    }
 
    void Update(int o, int l, int r, int p, int v) {
        if(l == r) {
            st[o] = v;
            return;
        } else {
            int m = l + r >> 1;
            if(p <= m)
                Update(ls, l, m, p, v);
            if(p >= m + 1)
                Update(rs, m + 1, r, p, v);
            PushUp(o);
        }
    }
 
    int Query(int o, int l, int r, int ql, int qr) {
        if(ql <= l && r <= qr) {
            return st[o];
        } else {
            int m = l + r >> 1;
            int res = 0;
            if(ql <= m)
                res = res | Query(ls, l, m, ql, qr);
            if(qr >= m + 1)
                res = res | Query(rs, m + 1, r, ql, qr);
            return res;
        }
    }
#undef ls
#undef rs
} st;
 
char s[200005];
 
void test_case() {
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    for(int i = 1; i <= n; ++i)
        st.a[i] = 1 << (s[i] - 'a');
    st.Build(1, 1, n);
    /*for(int i = 1; i <= n; ++i)
        printf("%d ", st.Query(1, 1, n, i, i));
    putchar('
');*/
    int q;
    scanf("%d", &q);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op == 1) {
            int x;
            char ch[2];
            scanf("%d%s", &x, ch);
            st.Update(1, 1, n, x, 1 << (ch[0] - 'a'));
        } else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%d
", __builtin_popcount((uint)st.Query(1, 1, n, l, r)));
        }
    }
}

*E - Special Permutations

数字i在排列中的位置,总是(i-1)次i,1次1,n-i次i+1。相邻的两个排列最多改变了两个数的位置。

原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12149376.html