ICPC 2019-2020 North-Western Russia Regional Contest

Contest Info


Practice Link

Solved A B C D E F G H I J K L M
8/13 O O - - O - - O O O Ø - O
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


Problem A. Accurate Movement

签到题。

代码:


view code

#include <bits/stdc++.h>
using namespace std;
int ceil(int x, int y) {
    return (x + y - 1) / y;
}

int main() {
    int a, b, n;
    while (scanf("%d%d%d", &a, &b, &n) != EOF) {
        int res = ceil(n - b, b - a) + ceil(n - a, b - a);
        printf("%d\n", res);
    }
    return 0;
}

Problem B. Bad Treap

题意:
令Treap的一对二维点权为\((f, sin(x))\),现在要给出\(n\)\(x\),使得这个Treap的深度最大

思路:
考虑很小的时候,\(x = sin(x)\),那么它两维都是单调的,深度最大

代码:


view code

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    scanf("%d", &n);
    for (long long i = 1; i <= n; ++i)
        printf("%lld\n", i * 710 - 710 * 25000);
    return 0;
}

Problem E. Equidistant

题意:
给出一棵树,再给定\(m\)个点,现在要找一个点,使得这个点到\(m\)个点的距离相等

思路:
\(m\)个点作为起点跑多源最短路,但是同时要记录到点\(x\)的最短路径条数,当最短路径条数为\(m\)的时候,那么这个点就是合法的

代码:


view code

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int n, m;
int dep[N], sze[N], a[N], vis[N];
vector<vector<int> >G;

void gao() {
    queue<int> q;
    for (int i = 1; i <= m; ++i) q.push(a[i]);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (auto &v : G[u]) {
            if (dep[v] == 0 || dep[v] == dep[u] + 1) {
                dep[v] = dep[u] + 1;
                sze[v] += sze[u];
                if (sze[v] == m) {
                    printf("YES\n%d\n", v);
                    return ;
                }
                if (!vis[v]) {
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
    puts("NO");
}

int main() {
    while (scanf("%d %d", &n, &m) != EOF) {
        G.clear();
        G.resize(n + 1);
        memset(dep, 0, sizeof dep);
        memset(sze, 0, sizeof sze);
        memset(vis, 0, sizeof vis);
        for (int i = 1, u, v; i < n; ++i) {
            scanf("%d %d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        for (int i = 1; i <= m; ++i) {
            scanf("%d", a + i);
            dep[a[i]] = 1;
            sze[a[i]] = 1;
            vis[a[i]] = 1;
        }
        if (n == 1) {
            puts("YES\n1");
        } else {
            gao();
        }
    }
    return 0;
}

Problem H. High Load Database

题意:
给出\(n\)个数\(a_i(\sum a_i \leq 10^6)\)\(q\)次询问给出一个\(t_i\),问将这\(n\)个数分成若干个连续段,使得每段之和不超过\(t_i\)的最小段数

思路:
考虑单次询问显然可以贪心合并,但是我们可以维护一个前缀和,每次二分跳下一个位置,所以处理一个询问的时间是\(O(\text{段数}logn)\)
并且考虑\(\sum a_i \leq 10^6\),所以所有可行询问的总段数不会很多,直接暴力即可。

代码:


view code

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, q, Max, a[N], sum[N], ans[N], vis[N]; 

int getans(int limit) {
    if (vis[limit]) return ans[limit];
    vis[limit] = 1;
    if (Max > limit) {
        return ans[limit] = -1;
    }
    if (limit <= 1000) {
        int res = 1, pre = 0;
        for (int i = 1; i <= n; ++i) {
            if (a[i] + pre <= limit) {
                pre += a[i];
            } else {
                pre = a[i];
                ++res;
            }
        }
        return ans[limit] = res;
    } else {
        int res = 0, pos = 0;
        while (pos < n) {
            ++res;
            int nx = upper_bound(sum + 1, sum + 1 + n, limit + sum[pos]) - sum - 1;
            pos = nx; 
        }
        return ans[limit] = res;
    }
}

int main() {
    while (scanf("%d", &n) != EOF) {
        memset(vis, 0, sizeof vis);
        sum[0] = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", a + i);
            Max = max(Max, a[i]);   
            sum[i] = sum[i - 1] + a[i];
        }
        scanf("%d", &q);
        while (q--) {
            int need; scanf("%d", &need);
            int res = getans(need);
            if (res == -1) puts("Impossible");
            else printf("%d\n", res);
        }
    }
    return 0;
}

Problem I. Ideal Pyramid

代码:


view code

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;

struct node {
    int x, y, z;

    node() {}

    node(int x, int y, int z): x(x), y(y), z(z) {}
}a[N];

int n;
int x, y;

bool ok(int h) {
    int l = -INF, r = INF, u = INF, d = -INF;
    for (int i = 1; i <= n; ++i) {
        if (h < a[i].z) return false;
        int x = h - a[i].z;
        l = max(l, a[i].x - x);
        r = min(r, a[i].x + x);
        u = min(u, a[i].y + x);
        d = max(d, a[i].y - x);
    }
    if (l > r || d > u) return false;
    x = l, y = d;
    return true;
}

int main() {
    while (scanf("%d", &n) != EOF) {
        for (int i = 1; i <= n; ++i) {
            scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z);
        }
        int l = 0, r = INF, res = INF;
        x = INF, y = INF;
        while (r - l >= 0) {
            int mid = (l + r) >> 1;
            if (ok(mid)) {
                r = mid -1;
                res = mid;
            } else {
                l = mid + 1;
            }
        }
        ok(res);
        printf("%d %d %d\n", x, y, res);
    }
    return 0;
}

Problem J. Just the Last Digit

题意:
有一个\(n\)个点的有向图,\(i\)\(j\)有边,那么必然有\(i < j\)
现在给出\(a_{i, j} = i \rightarrow j\)的路径条数模\(10\)的结果,要你还原这个图。

思路:
正着推,考虑新加入一个点\(k\)的时候,我们枚举一个点\(i(i < k)\),如果\(i\)\(k\)通过点\(j(i < j < k)\)中转的路径之和模\(10\)不等于\(a_{i, j}\),那么\(i \rightarrow k\)这条边是存在的,否则不存在

代码:


view code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 510;

int n;
char a[N][N];
int res[N][N];

int main() {
    while (scanf("%d", &n) != EOF) {
        memset(res, 0, sizeof res);
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                scanf(" %c", &a[i][j]);
            }
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = i + 1; j <= n; ++j) {
                int sum = 0;
                for (int k = i + 1; k < j; ++k) {
                    if (res[i][k]) sum += a[k][j] - '0';
                }
                if ((sum + 1) % 10 == a[i][j] - '0') res[i][j] = 1;
            }
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                printf("%d", res[i][j]);
            }
            puts("");
        }
    }
    return 0;
}

Problem K. King’s Children

题意:
给出一个\(n \cdot m\)的矩形,上面的'.'表示空地,字母表示国王的儿子,'A'表示大儿子。
现在要给每个儿子划分城市,每个城市必须是一个矩形,每块空地只能属于一个城市,一个城市里面只能包含一个儿子。
但是大儿子划分得到的空地数量要尽可能的多,但不一定是最多。

思路:
对'A'找一个极大子矩形,挖空后将剩下的分完。
考虑两种分法:

  • 先竖向扩展,然后横向扩展
  • 先横向扩展,然后竖向扩展

这两种分法不可能同时不成立,不太知道为啥(猜的)。。

代码:


view code

#include <bits/stdc++.h>
using namespace std;
#define dbg(x...) do { cout << "\033[32;1m" << #x << " -> "; err(x); } while(0)
void err() { cout << "\033[39;0m" << endl; }
template <class T, class... Ts> void err(const T&arg, const Ts&... args) { cout << arg << " "; err(args...); }
const int N = 1e3 + 10;
const int INF = 0x3f3f3f3f;
int n, m, ax, ay;
char str[N][N], stra[N][N], strb[N][N];
int up[N][N], down[N][N];
int X[N], Y[N];

void gaoA(char str[][N], int l, int r) {
    int MinU = INF, MinD = INF;
    for (int i = l; i <= r; ++i) {
        MinU = min(MinU, up[ax][i]);
        MinD = min(MinD, down[ax][i]);
    }
    for (int i = l; i <= r; ++i) {
        for (int j = 1; j <= MinU; ++j) {
            str[ax - j + 1][i] = 'a';
        }
        for (int j = 1; j <= MinD; ++j) {
            str[ax + j - 1][i] = 'a';
        }
    }
    str[ax][ay] = 'A';
}

void gaoU(char str[][N]) {
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (str[i][j] > 'A' && str[i][j] <= 'Z') {
                up[i][j] = i;
                for (int o = 1; ; ++o) {
                    if (i - o < 1) break;
                    if (str[i - o][j] != '.') break;
                    up[i][j] = i - o;
                    str[i - o][j] = str[i][j] - 'A' + 'a';
                }
            }   
        }
    }
}

void gaoD(char str[][N]) {
    for (int i = 1; i <= n; ++i) {
        for (int j = m; j >= 1; --j) {
            if (str[i][j] > 'A' && str[i][j] <= 'Z') {
                down[i][j] = i;
                for (int o = 1; ; ++o) {
                    if (i + o > n) break;
                    if (str[i + o][j] != '.') break;
                    down[i][j] = i + o;
                    str[i + o][j] = str[i][j] - 'A' + 'a'; 
                }
            }
        }
    }
}

void gaoL(char str[][N]) {
    for (int j = 1; j <= m; ++j) {
        for (int i = 1; i <= n; ++i) {
            if (str[i][j] > 'A' && str[i][j] <= 'Z') {
                for (int o = j - 1; o >= 1; --o) {
                    int F = 1;
                    for (int k = up[i][j]; k <= down[i][j]; ++k) { 
                        if (str[k][o] != '.') {
                            F = 0;
                            break;
                        }
                    }
                    if (!F) break;
                    for (int k = up[i][j]; k <= down[i][j]; ++k) {
                        str[k][o] = str[i][j] - 'A' + 'a';
                    }
                }
            }
        }
    }
}

void gaoR(char str[][N]) {
    for (int j = m; j >= 1; --j) {
        for (int i = 1; i <= n; ++i) { 
            if (str[i][j] > 'A' && str[i][j] <= 'Z') { 
                for (int o = j + 1; o <= m; ++o) { 
                    int F = 1; 
                    for (int k = up[i][j]; k <= down[i][j]; ++k) {
                        if (str[k][o] != '.') {
                            F = 0;
                            break;
                        }
                    }
                    if (!F) break;
                    for (int k = up[i][j]; k <= down[i][j]; ++k) {
                        str[k][o] = str[i][j] - 'A' + 'a';
                    }
                }
            }
        }
    }
}


void gaoU1(char str[][N]) {
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (str[i][j] > 'A' && str[i][j] <= 'Z') {
                for (int o = i - 1; o >= 1; --o) {
                    int F = 1;
                    for (int k = up[i][j]; k <= down[i][j]; ++k) {
                        if (str[o][k] != '.') {
                            F = 0;
                            break;
                        }
                    }
                    if (!F) break;
                    for (int k = up[i][j]; k <= down[i][j]; ++k) {
                        str[o][k] = str[i][j] - 'A' + 'a';
                    }
                }
            }
        }
    }
}

void gaoD1(char str[][N]) {
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (str[i][j] > 'A' && str[i][j] <= 'Z') {
                for (int o = i + 1; o <= n; ++o) {
                    int F = 1;
                    for (int k = up[i][j]; k <= down[i][j]; ++k) {
                        if (str[o][k] != '.') {
                            F = 0;
                            break;
                        }
                    }
                    if (!F) break;
                    for (int k = up[i][j]; k <= down[i][j]; ++k) {
                        str[o][k] = str[i][j] - 'A' + 'a';
                    }
                }
            }
        }
    }
}

void gaoL1(char str[][N]) { 
    for (int j = 1; j <= m; ++j) {
        for (int i = 1; i <= n; ++i) {
            if (str[i][j] > 'A' && str[i][j] <= 'Z') {
                up[i][j] = j; 
                for (int o = 1; ; ++o) {
                    if (j - o < 1) break; 
                    if (str[i][j - o] != '.') break;
                    up[i][j] = j - o; 
                    str[i][j - o] = str[i][j] - 'A' + 'a';
                }
            }   
        }
    }
}

void gaoR1(char str[][N]) {
    for (int j = m; j >= 1; --j) {
        for (int i = 1; i <= n; ++i) {
            if (str[i][j] > 'A' && str[i][j] <= 'Z') {
                down[i][j] = j;
                for (int o = 1; ; ++o) {
                    if (j + o > m) break;
                    if (str[i][j + o] != '.') break;
                    down[i][j] = j + o;
                    str[i][j + o] = str[i][j] - 'A' + 'a';
                }
            }
        }
    }
}

void print(char str[][N]) {
    for (int i = 1; i <= n; ++i) printf("%s\n", str[i] + 1);
}

bool ok(char str[][N]) {
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (str[i][j] == '.')
                return false;
        }
    }
    return true;
}

int main() {
    while (scanf("%d %d", &n, &m) != EOF) {
        for (int i = 1; i <= n; ++i) {
            scanf("%s", str[i] + 1);
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (str[i][j] == 'A') {
                    ax = i, ay = j;
                }
            }
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (i == 1) {
                    if (str[i][j] == '.' || str[i][j] == 'A') up[i][j] = 1;
                    else up[i][j] = 0;
                } else {
                    if (str[i][j] == '.' || str[i][j] == 'A') up[i][j] = up[i - 1][j] + 1;
                    else up[i][j] = 0;
                }
            }
        }
        for (int i = n; i >= 1; --i) {
            for (int j = 1; j <= m; ++j) {
                if (i == n) {
                    if (str[i][j] == '.' || str[i][j] == 'A') down[i][j] = 1;
                    else down[i][j] = 0;
                } else {
                    if (str[i][j] == '.' || str[i][j] == 'A') down[i][j] = down[i + 1][j] + 1;
                    else down[i][j] = 0;
                }
            }
        }
        // get A size
        int Max = -1, Maxl = -1 ,Maxr = -1;
        for (int l = 1; l <= m; ++l) {
            int MinU = INF, MinD = INF;
            for (int r = l; r <= m; ++r) {
                MinU = min(MinU, up[ax][r]);
                MinD = min(MinD, down[ax][r]);
                if (r >= ay && l <= ay) {
                    if (Max < (r - l + 1) * (MinU + MinD - 1)) {
                        Maxl = l, Maxr = r, Max = (r - l + 1) * (MinU + MinD - 1);
                    }
                }
            }
        }
        // color A size
        gaoA(str, Maxl, Maxr);
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                stra[i][j] = str[i][j];
                strb[i][j] = str[i][j];
            }
        }

        gaoU(stra);
        gaoD(stra);
        gaoL(stra);
        gaoR(stra);

        gaoL1(strb);
        gaoR1(strb);
        gaoU1(strb);
        gaoD1(strb);

        if (ok(strb)) print(strb);
        else if (ok(stra)) print(stra);
        else assert(0);
    }
    return 0;
}

Problem M. Managing Difficulties

签到题。

代码:


view code

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e3 + 10;
int n, a[N];
unordered_map <int, int> mp;

int main() {
    int _T; scanf("%d", &_T);
    while (_T--) {
        mp.clear();
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) scanf("%d", a + i);
        ll res = 0;
        for (int i = n; i >= 1; --i) ++mp[a[i]];
        for (int i = 1; i <= n; ++i) {
            --mp[a[i]];
            for (int j = i - 1; j >= 1; --j) {
                int x = 2 * a[i] - a[j];
                if (mp.count(x)) {
                    res += mp[x];
                }       
            }
        }
        printf("%lld\n", res);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Dup4/p/11968817.html