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;
}
原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14498043.html