zoukankan      html  css  js  c++  java
  • 2019 ICPC Latin American

    2019-2020 ACM-ICPC Latin American Regional Programming Contest

    D - Dazzling stars

    大意:

    平面上有许多点,每个点有权值,问是否存在一条直线,令这条直线按照某个方向移动,使其经过的点权值不下降,且能经过所有点。

    思路:

    每个点向权值比它小的所有点连成向量,将所有向量的起点移动到原点,如果所有向量都位于某条过原点的直线的一侧,则所求直线存在。将所有向量根据角度排序,判断是否有相邻向量夹角大于180度即可。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2000;
    const double pi = acos(-1);
    
    int x[N], y[N], b[N];
    vector<double> u;
    double cal(int x, int y) {
        if (x == 0) return y > 0 ? pi / 2 : -pi / 2;
        if (y == 0) return x > 0 ? 0 : pi;
        double ans = atan(double(y) / x);
        if (x > 0) return ans;
        return ans + pi;
    }
    bool check() {
        if (u.size() < 2) return true;
        double y = u.back() - pi * 2;
        for (auto x : u) {
            if (x - y + 1e-9 >= pi) return true;
            y = x;
        }
        return false;
    }
    int main() {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> x[i] >> y[i] >> b[i];
            for (int j = 0; j < i; j++) {
                if (b[i] < b[j])
                    u.push_back(cal(x[i] - x[j], y[i] - y[j]));
                else if (b[i] > b[j])
                    u.push_back(cal(x[j] - x[i], y[j] - y[i]));
            }
        }
        sort(u.begin(), u.end());
        if (check())
            cout << "Y
    ";
        else
            cout << "N
    ";
        return 0;
    }
    

    E - Eggfruit Cake

    模拟题

    #include <bits/stdc++.h>
    
    using namespace std;
    #define int long long
    int const MAXN = 2e5 + 10;
    int n, m, T;
    int go[MAXN];
    signed main() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        string s;
        cin >> s;
        int l = s.size();
        s = s + s;
        cin >> n;
        int pos = 2 * l;
        for (int i = 2 * l - 1; i >= 0; i--) {
            if (s[i] == 'E') pos = i;
            go[i] = pos;
        }
        int ans = 0;
        for (int i = 0; i < l; i++) {
            if (go[i] == 2 * l) continue;
            int d = go[i] - i;
            if (n - d <= 0) continue;
            ans += (n - d);
        }
        cout << ans;
        return 0;
    }
    

    F - Fabricating Sculptures

    大意:

    堆 A 个箱子,第 k 层箱子不能比第 k+1 层箱子多,最下一层有 B 个箱子,求方案数。

    思路:

    $dp[i][j] (表示放置了 i 个格子,最上面一层有 j 个格子的方案数,)dp[i][j]=∑^S_{x=j}dp[i−j][x]∗(x−j+1)$

    但是这样就是n^3的复杂度,所以需要维护

    (f1[i][j]=dp[i][1]+dp[i][2]+dp[i][3].....+dp[i][j])以及

    (f2[i][j]=dp[i][1]*1+dp[i][2]*2+dp[i][3]*3+....+dp[i][j]*j)这个两个前缀和,然后更新dp的时候直接(O(1))更新即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 5e3 + 5;
    #define int LL
    typedef long long LL;
    LL const mod = 1e9 + 7;
    LL dp[N][N], n, m, f1[N][N], f2[N][N];
    signed main() {
        cin >> m >> n;
        dp[m][m] = 1;
        f1[m][m] = 1;
        f2[m][m] = m;
        for (int i = m + 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                dp[i][j] = (-(f1[i - j][m] - f1[i - j][j - 1]) * (j - 1) % mod +
                            (f2[i - j][m] - f2[i - j][j - 1]) % mod) %
                           mod;
            }
            for (int j = 1; j <= m; j++) {
                f1[i][j] = (f1[i][j - 1] + dp[i][j]) % mod;
                f2[i][j] = (f2[i][j - 1] + dp[i][j] * j % mod) % mod;
            }
        }
        LL res = 0;
        for (int i = 1; i <= m; i++) {
            res += dp[n][i];
            res %= mod;
        }
        cout << (res + mod) % mod << endl;
        return 0;
    }
    

    I - Improve SPAM

    大意:

    一个邮件系统,其中有一些是中转站,每个中转站都会将收到的邮件发给子节点,子节点可能是中转站也可能是用户,现在从一号点出一封邮件,问每个用户总共会收到多少封邮件,以及一共有多少个用户收到邮件

    思路:

    直接拓扑排序去做即可,每次将父节点的邮件传给子节点

    #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 = 2e3 + 10, MAXM = MAXN * MAXN, mod = 1e9 + 7;
    int n, m, T, e[MAXM], ne[MAXM], idx, h[MAXN], val[MAXN], l, din[MAXN], f[MAXN];
    
    void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
    
    signed main() {
        n = read(), l = read();
        memset(h, -1, sizeof h);
        for (int i = 1, t; i <= l; ++i) {
            t = read();
            for (int j = 1, k; j <= t; ++j) {
                k = read();
                add(i, k);
                din[k]++;
            }
        }
        int S = 1;
        val[S] = 1;
        f[1] = 1;
        queue<int> q;
        for (int i = 1; i <= n; ++i)
            if (!din[i]) {
                q.push(i);
            }
        while (q.size()) {
            auto t = q.front();
            q.pop();
            for (int i = h[t]; ~i; i = ne[i]) {
                int j = e[i];
                val[j] += val[t];
                val[j] %= mod;
                f[j] |= f[t];
                din[j]--;
                if (!din[j]) q.push(j);
            }
        }
        int res1 = 0, res2 = 0;
        for (int i = l + 1; i <= n; ++i) {
            res1 += val[i];
            res1 %= mod;
            res2 += f[i];
        }
        cout << res1 % mod << " " << res2;
        return 0;
    }
    

    K - Know your Aliens

    大意:

    给出一个字符串,A代表将i带进多项式得到负值,H代表得到正值,现在需要构造一个多项式,使其满足条件

    思路:

    零点存在定理,如果相邻两个字符不同,那么必然存在零点,这样就可以得到一个零点式表示的多项式,将其化为系数表示即可

    #include <bits/stdc++.h>
    
    #define int long long
    using namespace std;
    
    int const MAXN = 2e5 + 10;
    const double PI = acos(-1);
    int n, m, T;
    int zero[MAXN], b[MAXN];
    int idx = 0;
    
    //从低到高递推求系数,x为零点坐标
    void _Get_xi() {
        b[1] = 1;
        for (int i = 1; i <= idx; i++) {
            for (int j = i + 1; j >= 1; j--) {
                b[j] = b[j - 1];
            }
            for (int j = 1; j <= i; j++) {
                b[j] += b[j + 1] * zero[i];
            }
        }
    }
    
    signed main() {
        string s;
        cin >> s;
        for (int i = 0; i < s.size() - 1; ++i) {
            if (s[i] != s[i + 1]) {
                zero[++idx] = 2 * i + 3;
            }
        }
        if (idx != 0)
            _Get_xi();
        else {
            cout << 0 << endl;
            if (s[0] == 'H')
                cout << 1 << endl;
            else
                cout << -1 << endl;
            return 0;
        }
        int flag = 1;
        cout << idx << endl;
        if (s[0] == 'A' && (idx % 2 == 0)) flag = -1;
        if (s[0] == 'H' && (idx % 2 == 1)) flag = -1;
        for (int i = idx + 1; i >= 1; i--) {
            cout << flag * b[i];
            if (i > 1) cout << ' ';
            flag = -flag;
        }
        return 0;
    }
    

    L - Leverage MDT

    大意:

    现在有一个n*m的矩阵,元素为B和G,G代表好的点,B代表坏的点,现在可以将每一行翻转(B变G,G变B)或者不翻转,问满足全部由G组成的正方形面积有多大

    思路:

    因为都可以翻转,那么到底是B和G就没有关系了,所以可以先预处理出每个点左边到他本身相同的字符有多少个

    然后对于每列做两次单调栈(类似最大子矩阵)即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e3 + 5;
    typedef long long LL;
    int n, m;
    int mp[N][N], l[N][N], r[N][N];
    int main() {
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            string s;
            cin >> s;
            s = " " + s;
            for (int j = 1; j <= m; j++) {
                if (s[j] == s[j - 1])
                    mp[i][j] = mp[i][j - 1] + 1;
                else
                    mp[i][j] = 1;
            }
        }
        int res = 0;
        for (int j = 1; j <= m; j++) {
            stack<int> st;
            for (int i = 1; i <= n; i++) {
                while (!st.empty() && mp[st.top()][j] >= mp[i][j]) st.pop();
                if (st.empty())
                    l[i][j] = 1;
                else
                    l[i][j] = st.top() + 1;
                st.push(i);
            }
            while (!st.empty()) st.pop();
            for (int i = n; i >= 1; i--) {
                while (!st.empty() && mp[st.top()][j] >= mp[i][j]) st.pop();
                if (st.empty())
                    r[i][j] = n;
                else
                    r[i][j] = st.top() - 1;
                st.push(i);
                int tmp = min(r[i][j] - l[i][j] + 1, mp[i][j]);
                res = max(tmp, res);
            }
        }
        cout << (LL)res * res << endl;
        return 0;
    }
    

    M - Mountain Ranges

    签到

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    typedef long long LL;
    int n, x, a[N], res = 0, t = 0;
    int main() {
        cin >> n >> x;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            if (i == 0)
                t = 1;
            else {
                if (a[i] - a[i - 1] <= x)
                    t++;
                else
                    t = 1;
            }
            res = max(res, t);
        }
        cout << res << endl;
        return 0;
    }
    
  • 相关阅读:
    一个、说到所有的扩展指标
    时序图、流程图
    流程图总结
    UML活动图与流程图的区别
    类图与对象图
    app的描述-软件的描述
    UML的目标
    软件建模的用途
    Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]
    Serializable 和 Parcelable 区别
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14498043.html
Copyright © 2011-2022 走看看