Codeforces Round #517(Div 2)

比赛链接:传送门

A. Golden Plate(简单思维题+暴力)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAX_N = 1e6 + 5;

int main()
{
    ll ans = 0;
    ll w, h, k;
    cin >> w >> h >> k;
    while (k--) {
        ans += 2*w+2*h-4;
        w -= 4;
        h -= 4;
    }
    cout << ans << endl;
    return 0;
}
View Code

B. Curiosity Has No Limits(暴力dfs)

题目大意:

  给你两个长度为n的数组a,b,然后让你构造一个数组t使得ti|ti+1 = ai,ti&ti+1 = bi

  (0 ≤ ai, bi, ti ≤ 3, 2 ≤ n ≤ 105

思路:

  对当前位置的ai,bi,和前置的ti,ti+1的选择是很少的。

  所以可以把这个ti+1全都预处理出来放在vector里面,用到的时候直接遍历vector即可。

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1e5 + 5;
struct Node{
    int t1, t2;
    Node(int _x = 0, int _y = 0) : t1(_x), t2(_y) {}
};

int N;
int a[MAX_N], b[MAX_N];
vector <Node> V[4][4];
vector <int> ans;

void init()
{
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            int a = i|j;
            int b = i&j;
            V[a][b].push_back(Node(i, j));
        }
    }
//    for (int i = 0; i < 4; i++) {
//        for (int j = 0; j < 4; j++) {
//            for (int k = 0; k < V[i][j].size(); k++) {
//                cout << i << ' ' << j << ' ' << V[i][j][k].t1 << ' ' << V[i][j][k].t2 << endl;
//            }
//            cout << endl;
//        }
//    }
}

bool dfs(int dep, int pret)
{
    int cura = a[dep];
    int curb = b[dep];
    if (!V[cura][curb].size()) {
        cout << "NO" << endl;
        exit(0);
    }
    for (unsigned int k = 0; k < V[cura][curb].size(); k++) {
        Node cur = V[cura][curb][k];
        if (dep == N-1) {
            if (cur.t1 == pret) {
                cout << "YES" << endl;
                ans.push_back(cur.t2);
                return true;
            }
            else
                continue;
        }
        if (cur.t1 == pret) {
            if (dfs(dep+1, cur.t2)) {
                ans.push_back(cur.t2);
                return true;
            }
        }
    }
    return false;
}

int main()
{
    init();
    cin >> N;
    for (int i = 1; i <= N-1; i++)
        scanf("%d", a+i);
    for (int i = 1; i <= N-1; i++)
        scanf("%d", b+i);

    for (unsigned int k = 0; k < V[a[1]][b[1]].size(); k++) {
        Node cur = V[a[1]][b[1]][k];
        if (dfs(1, cur.t1)) {
            ans.push_back(cur.t1);
            break;
        }
    }
    if (!ans.size()) {
        cout << "NO" << endl;
        return 0;
    }
    for (int i = N-1; i > 0; i--) {
        cout << ans[i] << ' ';
    }
    cout << ans[0] << endl;
    return 0;
}
View Code

C. Cram Time(贪心+暴力)

题目大意:

  第一天的时间为a,第二天的时间为b,然后有无限本书,阅读时间对应从1开始的正整数,且每个正整数只能用一次。

  问:使得读的书最多的情况下,怎么安排这两天的读书顺序。

  (1 ≤ a,b ≤ 109

思路:

  肯定是优先把时间短的书读掉。所以从时间为1的书开始累加,直到时间和sum将要大于a+b。标记之前所有加过的时间。

  然后原来的总时间a+b要减去比sum多出来的部分。为了方便地防止减掉之后小于零,直接取a、b中较大者减掉这个差值。

  现在a+b就等于sum了,然后分配之前累加的书。分配出的和到达a之后剩余的自然就是b,然后贪心地从剩余最大的开始分就可以了。

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1e6 + 5;

bool vis[MAX_N];

int main()
{
    int a, b;
    cin >> a >> b;
    int sum = a+b;
    int tot = 0;
    for (int i = 1; sum >= i; i++) {
        sum -= i;
        vis[++tot] = true;
    }
    if (sum) {
        if (a > b)
            a -= sum;
        else
            b -= sum;
    }

    int cnta = 0;
    for (int i = tot; i >= 1; i--) {
        if (i <= a) {
            a -= i;
            vis[i] = false;
            cnta++;
        }
    }
    cout << cnta << endl;
    bool firstprint = true;
    for (int i = 1; i <= tot; i++) {
        if (!vis[i]) {
            if (firstprint)
                firstprint = false;
            else
                printf(" ");
            printf("%d", i);
        }
    }
    cout << endl;
    cout << tot-cnta << endl;
    firstprint = true;
    for (int i = 1; i <= tot; i++) {
        if (vis[i]) {
            if (firstprint)
                firstprint = false;
            else
                printf(" ");
            printf("%d", i);
        }
    }
    cout << endl;
    return 0;
}
View Code

D. Minimum path(bfs)

题目大意:

  给定一个N*N的小写字母矩阵,从左上角开始走到右下角,每次可以向下走或者向右走。

  路径上的字符可以构成一个长度为2*N-1的字符串。你可以对这个字符串修改k次。

  求修改k次后的字符串中,字典序最小的一个。

懵逼:

  比赛的时候想到用dp,同时维护字符串和剩余的修改次数。

  但是字符串会占O(n)的内存,不过可以用滚动数组优化掉。

  然后字符串的比较又会耗时O(n),Becky_w说用哈希什么的,我硬是没想出来。

  补题的时候想到可以直接维护答案,结果敲完发现和wyb一起迷之MLE。。

  最后就是数据结构大佬Dilthey天秀,用数组模拟队列,然后跑bfs就AC了。

思路:

  从左上角开始往右下角跑bfs,保证每层和左上角的曼哈顿距离都是一样的,每层都用一个队列保存。

  每层跑出当前层的最优解,直接存入答案,对于跑出的非最优解直接舍弃掉(ind = -1)。

  维护剩余更改次数k:

    k不为0的时候才维护,如果当前位置的字符为'a',那么k不变,否则k--。

  维护答案:

    当前剩余的k如果不为0的话那么这个位置的答案就为'a',否则为当前这一层的最小的字符。

  滚动数组模拟队列:

    flag 标识当前队列使用的维度,!flag 标识下一层队列的维度。

    tot[flag],tot[!flag]表示队列的长度。

  时间复杂度:

    bfs遍历了原矩阵,所以时间复杂度是O(n2)。

  

  宣传一波大佬博客:Dilthey的博客

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 2000 + 5;
const int dx[2] = {1, 0};
const int dy[2] = {0, 1};
#define nx cur.x+dx[k]
#define ny cur.y+dy[k]

struct Node {
    char c;
    int x, y, resk;
    Node(char _c = '{', int _x = 0, int _y = 0, int k = 0) : c(_c), x(_x), y(_y), resk(k) {}
    bool operator < (const Node& a) const {
        if (resk == a.resk)
            return c < a.c;
        return resk > a.resk;
    }
};

int N, K;
char mat[MAX_N][MAX_N];
string ans;
int tot[2], ind[MAX_N][MAX_N];
Node f[2][MAX_N << 1];

inline bool check(int x, int y)
{
    if (x < 1 || x > N || y < 1 || y > N)
        return false;
    return true;
}

void bfs()
{
    int flag = 0; // 滚动数组的下标,f的第一维
    tot[0] = tot[1] = 0;
    if (mat[1][1] == 'a')
        f[flag][tot[flag]++] = Node('a', 1, 1, K);
    else
        f[flag][tot[flag]++] = Node(K?'a':mat[1][1], 1, 1, K?K-1:0);
    ans += K?'a':mat[1][1];
    ind[1][1] = 0;
    while (tot[flag]) {
        char tar = 'z'+1;

        for (int i = 0; i < tot[flag]; i++) {
            Node cur = f[flag][i];
            if (ind[cur.x][cur.y] < 0)
                continue;
            for (int k = 0; k < 2; k++) if (check(nx, ny)) {
                int nk = cur.resk;
                char nc = mat[nx][ny];
                if (nk > 0 && nc != 'a') {
                    nk--;
                    nc = 'a';
                }
                Node nxt(nc, nx, ny, nk);
                tar = min(tar, nc);
                if (ind[nx][ny] < 0) {
                    f[!flag][tot[!flag]] = nxt;
                    ind[nx][ny] = tot[!flag];//保存坐标用于下次删去
                    tot[!flag]++;
                }
                else {
                    f[!flag][ind[nx][ny]] = min(f[!flag][ind[nx][ny]], nxt);
                }
            }
        }
        if (tar == 'z'+1)
            break;

        for (int i = 0; i < tot[!flag]; i++) {
            Node cur = f[!flag][i];
            if (cur.c > tar)
                ind[cur.x][cur.y] = -1;//删去非最优的
        }
        ans += tar;
        tot[flag] = 0;
        flag = !flag;
    }
}

int main()
{
    cin >> N >> K;
    for (int i = 1; i <= N; i++)
        scanf("%s", mat[i]+1);
    memset(ind, -1, sizeof ind);

    ans = "";
    bfs();
    cout << ans << endl;
    return 0;
}
/*
3 0
irk
thm
aba
*/
View Code
原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9838043.html