zoukankan      html  css  js  c++  java
  • ICPC 2019North-Western Russia (7/13)

    ICPC 2019-2020 North-Western Russia Regional Contest

    A - Accurate Movement

    签到

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    int const MAXN = 2e5 + 10;
    int n, m, T;
    
    int main() {
        int a, b, c;
        cin >> a >> b >> c;
        if (c == b)
            cout << 1;
        else if ((c - b) % (b - a))
            cout << 2 * ((c - b) / (b - a)) + 3;
        else
            cout << 2 * ((c - b) / (b - a)) + 1;
        return 0;
    }
    

    B - Bad Treap

    大意:

    给出笛卡尔树的定义,现在要求给出 n 个点对 ( x , sin( x ) ),使得笛卡尔树的高度尽可能大

    思路:

    题意就是要找到一个长度为n的递增序列,且sin(ai)也是递增的

    考虑到如果sinx极小,那么sin2x sin3x....一直到sinnx都是很小的,所以只需要找到一个最最最接近于0的sin值,然后输出这个点的倍数即可,因为不能超过2^32,所以向左偏1e9

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    typedef long long LL;
    struct node {
        double sin;
        int x;
    } a[N];
    bool cmp(node a, node b) { return a.sin < b.sin; }
    int main() {
        int cnt = 0;
        for (int i = 1; i <= 1e5; i++) {
            if(sin(i)>0)
            a[cnt].x = i, a[cnt++].sin = sin(i);
        }
        sort(a, a + cnt, cmp);
        int n;
        cin >> n;
        for (int i = 0; i < n;i++){
            cout << (LL)a[0].x * i -100000000<< endl;
        } return 0;
    }
    

    E - Equidistant

    大意:

    给出n个点的树,然后上面有m个特殊点,要求求出一个点,使得这个点到所有的m个点的距离都相同

    思路:

    bfs,先将每个特殊点都入队,然后每次到一个数,都看是否有别的点先到达,只有同时到达或者第一次到达才把这个点入队,还要标记一下每个点同时被多少点到达,最后看是否存在一个点同时被m个特殊点到达即可

    #include <bits/stdc++.h>
    
    #define int long long
    using namespace std;
    
    inline int read() {
        int s = 0, w = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') w = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
        return s * w;
    }
    
    int const MAXN = 3e5 + 10, MAXM = MAXN * 3;
    int n, m, T, vis[MAXN], dis[MAXN];
    int idx, e[MAXM], h[MAXN], ne[MAXM], num[MAXN], inque[MAXN];
    queue<int> q;
    
    void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
    
    signed main() {
        n = read(), m = read();
        for (int i = 1; i <= n + 10; ++i) h[i] = -1;
        for (int i = 1; i <= n - 1; ++i) {
            int a, b;
            a = read(), b = read();
            add(a, b), add(b, a);
        }
        for (int i = 1; i <= m; ++i) {
            int c;
            c = read();
            dis[c] = 0;
            num[c] = 1;
            vis[c] = 1;
            inque[c] = 1;
            q.push(c);
        }
        while (q.size()) {
            auto t = q.front();
            q.pop();
            inque[t] = 0;
            for (int i = h[t]; ~i; i = ne[i]) {
                int j = e[i];
                if ((dis[j] && dis[j] != dis[t] + 1) || vis[j] == 1) {
                    vis[j] = 1;
                    continue;
                }
                dis[j] = dis[t] + 1;
                num[j] += num[t];
                if (!inque[j]) q.push(j), inque[j] = 1;
            }
        }
        int flg = 0, res = 0;
        for (int i = 1; i <= n; ++i) {
            if (num[i] == m) {
                flg = 1;
                res = i;
                break;
            }
        }
        if (!flg)
            printf("NO
    ");
        else {
            printf("YES
    ");
            printf("%d
    ", res);
        }
        return 0;
    }
    

    H - High Load Database

    大意:

    给出n(2e5)个数,以及q(1e5)个询问,每次询问给出一个数x,问将n个数最少分成多少个连续的段,才能使得每个段的和都小于等于x,不能就输出impossible,保证n个数的和不大于1e6

    思路:

    先求前缀和,然后对于每个询问二分去跳,每跳一次就是一个段,然后输出答案即可,需要注意的是,这个方法可能会因为x比较小,所以导致二分查询退化成了n的复杂度,那么整体复杂度最坏可能达到nq,但是这些x比较少,所以如果记忆化答案,就可以避免超时。可以先把1e6的答案都跑一遍存下来,也可以对于每次查询看之前是否查询过

    #include <bits/stdc++.h>
    
    #define int long long
    using namespace std;
    
    inline int read() {
        int s = 0, w = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') w = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
        return s * w;
    }
    
    int const N = 2e6 + 10;
    int n, m, T, sum[N], a[N];
    int res[N];
    signed main() {
        n = read();
        for (int i = 1; i <= n; i++) a[i] = read(), sum[i] = sum[i - 1] + a[i];
        int q = read();
        memset(res, -1, sizeof res);
        for (int i = 0; i <= sum[n]; i++) {
            int x = i;
            int tmp = x;
            int start = 1;
            int flag = 1;
            int cnt = 0;
            while (start <= n) {
                int pos = upper_bound(sum + start, sum + 1 + n, tmp) - sum;
                if (pos == start) {
                    flag = 0;
                    break;
                }
                start = pos;
                tmp = x + sum[pos - 1];
                cnt++;
            }
            if (!flag)
                res[x] = -1;
            else {
                res[x] = cnt;
            }
        }
        while (q--) {
            int x = read();
            if (x > sum[n]) {
                cout << 1 << endl;
            } else {
                if (res[x] != -1) {
                    cout << res[x] << endl;
                }
                else{
                    cout << "Impossible" << endl;
                }
            }
        }
        return 0;
    }
    

    I - Ideal Pyramid

    大意:

    给定 N 个柱子的坐标和高度,要求找到一个最小的四棱锥(斜面和底面夹角为45°),使得全部的柱子都在里面

    思路:

    因为斜面和底面夹角为45度,所以h<=R-max(dx,dy)

    这就将三维的问题转化为了2维的问题,分别考虑x和y,那么能够求出来金字塔底面的上下左右范围,然后取中心即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    typedef long long LL;
    int n;
    struct node {
        LL x, y, h;
    } a[N];
    LL INF = 0x3f3f3f3f3f3f3f;
    int main() {
        cin >> n;
        for (int i = 0; i < n; i++) cin >> a[i].x >> a[i].y >> a[i].h;
        LL u = INF, d = -INF, l = INF, r = -INF;
        for (int i = 0; i < n; i++) {
            u = min(u, a[i].x - a[i].h);
            d = max(d, a[i].x + a[i].h);
            l = min(l, a[i].y - a[i].h);
            r = max(r, a[i].y + a[i].h);
        }
        LL x = (u + d) / 2, y = (l + r) / 2;
        LL h = (max(d - u, r - l) + 1) / 2;
        cout << x << ' ' << y << ' ' << h;
        return 0;
    }
    

    J - Just the Last Digit

    大意:

    给出一个n*n的矩阵,其中(a_{i,j})是i到j的路径个数再对10取模,现在保证每条路都从较小编号的点连到较大编号的点,问能否求出每个点之间是否有边

    思路:

    对10取模是个幌子,我们先看没有这个限制的时候怎么做

    注意到两个点之间的路径只可能是:

    1.直接到达

    2.经过一个点间接到达

    如果求出i和j之间间接到达的路径数量,看是否和输入相同,就知道两个点是否有路径了。

    又因为保证了边都是从较小的点到较大的点,所以1号点和2号点是否有边是已知的,那么就可以一路推下去了。

    再考虑取模这个条件,那么只需要在计算路径个数的时候对10取模即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 500 + 5;
    typedef long long LL;
    int n, mp[N][N], res[N][N];
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%1d", &mp[i][j]);
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = i + 1; j <= n; j++) {
                for (int k = i + 1; k < j; k++) {
                    res[i][j] = (res[i][j] + res[i][k] * mp[k][j]) % 10;
                }
                if (res[i][j] == mp[i][j])
                    res[i][j] = 0;
                else
                    res[i][j] = 1;
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                cout << res[i][j];
            }
            cout << endl;
        }
        return 0;
    }
    

    M - Managing Difficulties

    大意:

    给出n(2e3)个数,要求求出满足:

    i < j < k且(a_j-a_i==a_k-a_j)的数对的数量

    思路:

    因为n比较小,所以可以想到直接枚举i和j,然后找他们和的一半出现的数量,一开始用的mulityset,一直T,因为还有t次询问,这样可能(O(n^2log(n)))的算法可能会卡爆,改成unordered_map就过了...

    #include <bits/stdc++.h>
    
    using namespace std;
    #define int long long
    int const MAXN = 2e3 + 10;
    int n, m, T;
    int a[MAXN];
    unordered_map<int, int> mp;
    signed main() {
        cin >> T;
        while (T--) {
            cin >> n;
            for (int i = 1; i <= n; i++) cin >> a[i];
            int ans = 0;
            for (int i = 1; i <= n - 2; i++) {
                mp.clear();
                mp[a[i + 1]]++;
                for (int k = i + 2; k <= n; k++) {
                    if ((a[i] + a[k]) % 2) {
                        if (mp.count(a[k]))
                            mp[a[k]]++;
                        else
                            mp[a[k]] = 1;
                        continue;
                    }
                    int j = (a[i] + a[k]) / 2;
                    if (mp.count(j)) ans += mp[j];
                    if (mp.count(a[k]))
                        mp[a[k]]++;
                    else
                        mp[a[k]] = 1;
                }
            }
            cout << ans << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    超前进位加法器
    Xilinx ISE 12.3 LED测试程序
    位图文件(BMP)格式以及Linux下C程序实现
    SPB16.3安装系列指导
    Debian6显卡驱动安装
    深入浅出之正则表达式
    一个在台积电工作3年的工程师写给学弟学妹们的信
    Debian下解决MP3标题乱码
    ubuntu下安装usbblaster(更新)
    乘法器的Verilog HDL实现
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14492740.html
Copyright © 2011-2022 走看看