Codeforces Round #617 (Div. 3) 题解

又是隔了一年才来补题的我

A、B水题就不用说了

C - Yet Another Walking Robot

C题我居然卡了一会,最后决定用map水,结果出来看了看题解,居然真的是map...没想到会出这样题解用stl的方法,是我失策了

#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
const int N = 100010 * 2;
char s[N];
typedef pair <int, int> p;
map <p, int> k;
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n;
        scanf("%d", &n);
        scanf("%s", s);
        k.clear();
        int c1 = 0, c2 = 0;
        int ans2 = 0x3f3f3f3f, ans1 = 0;
        k[make_pair(0, 0)] = 0;
        for (int i = 0; i < n; i++) {
            if (s[i] == 'L')    c1--;
            else if (s[i] == 'R')    c1++;
            else if (s[i] == 'U')    c2++;
            else    c2--;
            if (k.find(make_pair(c1, c2)) == k.end()) {
                k[make_pair(c1, c2)] = i + 1;
                continue;
            }
            int z = k[make_pair(c1, c2)];
            if (i - z < ans2 - ans1)
                ans2 = i + 1, ans1 = z + 1;
            k[make_pair(c1, c2)] = i + 1;
        }
        if (ans1 == 0)
            puts("-1");
        else
            printf("%d %d\n", ans1, ans2);
    }
    return 0;
}
//LRUD
// 6 LLLLUUURRRRDDDLL
// LLLLLLUUURRDDDL

D - Fight with Monsters

比较水,先处理出一定能杀死的,把最后一轮剩下的丢尽一个优先队列里(直接排序也行),从小到大判断要用几次秘密武器才能打怪成功,注意要判断优先队列是不是非空(不然就会TLE一次...

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
int hp[2 * 100010];
priority_queue < int, vector < int >, greater < int > > Q;
int main() {
    int n, a, b, k, ans = 0;
    scanf("%d %d %d %d", &n, &a, &b, &k);
    for (int i = 0; i < n; i++) {
        scanf("%d", &hp[i]);
        if (hp[i] % (a + b) == 0)
            Q.push(b);
        else {
            int res = hp[i] % (a + b);
            if (res <= a)
                ans++;
            else
                Q.push(res - a);
        }
    }
    while (k > 0 && !Q.empty()) {  //就是这里
        int u = Q.top(); Q.pop();
        int cnt = u / a;
        if (u % a != 0)    cnt++;    
        if (cnt > k)
            break;
        else
            ans++, k -= cnt;
    }
    printf("%d", ans);
    return 0;
}

E1 - String Coloring (easy version)

题解是贪心或者dp,而我是二分图染色(迷惑行为),主要还是没看出来本质是划分子集,所以用二分图水过了,简单说一下题解做法吧,因为两个字母不按照字母顺序就要交换,所以如果把每个编号的视为一组,那么同组就是递增的,反之也是一样,如果能划分成两个上升的子序列,那一定可以按题目方式染色,因为你可以把不同颜色的字母随意改变顺序。还有一个方法是贪心,这个方法很有意思,目前有两个序列,判断当前这个能不能加在1后面,如果不行,能不能加在2后面,都不行就不能划分了,这种贪心方式的正确性在于,首先新的字母,无论加在序列1还是2后面产生的效果都是最后一个变成了s[i],由于先考虑序列1后考虑序列2,所以序列二的结尾总是小于序列1的,所以先加在1后面能保证序列二结尾尽可能的小,从而保证了贪心的正确性。

#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
char s[1010];
vector < int > e[210];
int col[210];
inline void add(int a, int b) {
    e[a].push_back(b);
    e[b].push_back(a);
}
int ans = 0;
void dfs(int a, int c) {
    col[a] = c;
    for (int i = 0; i < e[a].size(); i++) {
        int u = e[a][i];
        if (col[u] == -1)
            dfs(u, (c + 1) % 2);
        else if (col[u] == col[a]) {
            ans = -1;
            return ;
        }
    }
}

int main() {
    int n;
    scanf("%d", &n);
    scanf("%s", s);
    memset(col, 0xff, sizeof(col));
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)
            if (s[i] > s[j])
                add(i, j);
    for (int i = 0; i < n; i++)
        if (col[i] == -1)
            dfs(i, 0);
    if (ans == -1)
        puts("NO");
    else {
        puts("YES");
        for (int i = 0; i < n; i++)
            printf("%d", col[i]);
    }
    return 0;
}

E2 - String Coloring (hard version)

下面这道题也很有意思,我刚做完的牛客比赛里正好有类似的题...有了easy版的推论,我们能看出就是最少分成几个不下降子序列,那就应用Dilworth定理,链划分的最少集合数等于最长反链长度,翻译成人话就是算最长下降子序列,这个nlogn的方法应该都知道,所以麻烦之处就在于划分,但是我们可以发现对于第i个字母s[i],以s[i]结尾的最长下降子序列长度就是它在的集合,首先相同长度一定是不下降的子序列,再者,对于s[i]而言,无法加到以大于s[i]结尾的序列后面,所以就只能成为一个新的序列。

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 2 * 1e5 + 10;
char s[N];
int dp[N], ans[N];
inline bool cmp(int a, int b) {
    return a > b;
}
int main() {
    int n;
    scanf("%d", &n);
    scanf("%s", s);
    int len = 1;
    dp[1] = s[0] - 'a';
    ans[0] = 1;
    for (int i = 1; i < n; i++) {
        if (s[i] - 'a' < dp[len]) {
            dp[++len] = s[i] - 'a';
            ans[i] = len;
        }
        else {
            int pos = lower_bound(dp + 1, dp + len + 1, s[i] - 'a', cmp) - dp;
            ans[i] = pos;
            dp[pos] = s[i] - 'a';
        }
    }
    printf("%d\n", len);
    for (int i = 0; i < n; i++)
        printf("%d ", ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cminus/p/12316615.html