首页 > 其他 > 详细

2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017)

时间:2019-10-13 09:15:18      阅读:118      评论:0      收藏:0      [点我收藏+]

 

2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017)

 

A - Concerts

$f[i][k]$ 表示在第 $i$ 个位置刚好匹配了 $k$ 个字符。转移方程 $$ f[i][k] = \sum_{i - j > h[s[k - 1]]} f[j][k - 1] $$

前缀和优化加滚动就行了。

好像可以直接用 $f[i][k]$ 表示前缀和,就没这么多事了。

技术分享图片
#include <bits/stdc++.h>

const int N = 1e5 + 7;
const int MOD = 1e9 + 7;

int dp[2][N], sum[2][N], h[N];
char s[N], t[N];

void M(int &a) {
    if (a >= MOD) a -= MOD;
}

int main() {
    freopen("in.txt", "r", stdin);
    int k, n;
    scanf("%d%d", &k, &n);
    for (int i = 0; i < 26; i++)
        scanf("%d", h + i);
    scanf("%s%s", t + 1, s + 1);
    for (int i = 1; i <= n; i++) {
        if (s[i] == t[1])
            dp[1][i] = 1;
        sum[1][i] =  sum[1][i - 1] + dp[1][i];
    }
    for (int j = 2; j <= k; j++) {
        int cur = j & 1, pre = cur ^ 1;
        memset(dp[cur], 0, sizeof(dp[cur]));
        memset(sum[cur], 0, sizeof(sum[cur]));
        for (int i = 1; i <= n; i++) {
            if (s[i] == t[j]) {
                int where = i - h[t[j - 1] - A] - 1;
                if (where > 0)
                    M(dp[cur][i] += sum[pre][where]);
            }
            //if (i == 2) printf("%d\n", dp[cur][i]);
            M(sum[cur][i] += sum[cur][i - 1]);
            M(sum[cur][i] += dp[cur][i]);
        }
    }
    printf("%d\n", sum[k & 1][n]);
    return 0;
}
View Code

 

D - Harry Potter and The Vector Spell

并查集合并每一列中两个 $1$,不在同一个集合里则对答案贡献为 $1$

技术分享图片
#include <bits/stdc++.h>

const int N = 1e5 + 7;

int fa[N];

int getfa(int x) {
    return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}

std::vector<int> G[N];

int main() {
    int n, m;
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= m; i++) {
        fa[i] = i;
        int k;
        scanf("%d", &k);
        while (k--) {
            int u;
            scanf("%d", &u);
            G[u].push_back(i);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (G[i].size() == 0) continue;
        if (G[i].size() == 1) { ans++; continue; }
        int u = G[i][0], v = G[i][1];
        u = getfa(u);
        v = getfa(v);
        if (u != v) {
            ans++;
            fa[u] = v;
        }
    }
    printf("%d\n", ans);
}
View Code

 

F - Binary Transformations

贪心地考虑,先把不匹配的 $1$ 从大到小消掉,再把不匹配的 $0$ 从小到大加上。但是如果存在一些匹配了的 $1$ 它们的花费特别大,就不是最优的。

那么就枚举多消去几个已经匹配了的 $1$,这部分肯定也是从大到小优。

用multiset维护即可。

技术分享图片
#include <bits/stdc++.h>
#define ll long long

const int N = 1e4 + 7;

std::multiset<ll, std::greater<ll> > st1;
std::multiset<ll> st2;
std::vector<ll> vec;
int n;
ll c[N];
ll sum;
char a[N], b[N];

ll solve(int cnt) {
    ll ans = 0;
    ll s = sum;
    if (cnt)
        st1.insert(vec[cnt - 1]), st2.insert(vec[cnt - 1]);
    for (auto it: st1) {
        s -= it;
        ans += s;
    }
    for (auto it: st2) {
        s += it;
        ans += s;
    }
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", c + i);
    scanf("%s", a + 1);
    scanf("%s", b + 1);
    for (int i = 1; i <= n; i++) {
        if (a[i] != b[i]) {
            if (a[i] == 1) st1.insert(c[i]);
            else st2.insert(c[i]);
        } else {
            if (a[i] == 1) vec.push_back(c[i]);
        }
        if (a[i] == 1) sum += c[i];
    }
    std::sort(vec.begin(), vec.end(), std::greater<ll>());
    ll ans = 1e18;
    for (int i = 0; i <= vec.size(); i++)
        ans = std::min(ans, solve(i));
    printf("%lld\n", ans);
    return 0;
}
View Code

 

G - Robots

技术分享图片
#include <bits/stdc++.h>

#define ll long long

const int N = 1e4 + 7;

struct In {
    ll a, t;
    bool operator < (const In &rhs) const {
        return a > rhs.a;
    }
} in[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%lld%lld", &in[i].a, &in[i].t);
    ll v = 0;
    double ans1 = 0;
    for (int i = 0; i < n; i++) {
        ans1 += v * in[i].t + 0.5 * in[i].a * in[i].t * in[i].t;
        v += in[i].a * in[i].t;
    }
    std::sort(in, in + n);
    v = 0;
    double ans = 0;
    for (int i = 0; i < n; i++) {
        ans += v * in[i].t + 0.5 * in[i].a * in[i].t * in[i].t;
        v += in[i].a * in[i].t;
    }
    printf("%.1f\n", ans - ans1);
    return 0;
}
View Code

 

J - Cunning Friends

三个人的nim...

如果全是 $1$,那么 $n \equiv 0$  (mod $3$)时必输,否则必胜。

如果只有一个不是 $1$,如果  $n \equiv 0$  (mod $3$),第一个人把 非 $1$ 那堆取出 $1$ 就必胜,否则把那一堆取光。

如果有两个不是 $1$,且至少有一个 $2$ 并且 $1$ 的个数不是 $3$ 的倍数,第一个人都可以把一堆取光或者取剩下 $1$ 使得自己赢,否则必败,另外两个人都可以让 $n \equiv 0$  (mod $3$)

如果大于两个,另外两个人的操作空间比第一个人大,就可以让第一个人必败了。

技术分享图片
#include <bits/stdc++.h>

int main() {
    int n;
    int cnt1 = 0, cnt2 = 0;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        if (x == 1) cnt1++;
        else if (x == 2) cnt2++;
    }
    if (cnt1 == n) puts(n % 3 == 0 ? "Lose" : "Win");
    else if (cnt1 == n - 1) puts("Win");
    else if (cnt1 == n - 2) puts((cnt2 && cnt1 % 3 != 0) ? "Win" : "Lose");
    else puts("Lose");
}
View Code

 

K - Escape Room

对于 $n$ 它的最长上升子序列肯定是 $1$,对于 $n-1$,如果它在 $n$ 后面那么肯定是 $1$,如果在 $n$ 前面那么肯定是 $2$,但是放后面会使得字典序更小。

那么就按最长上升子序列的值排个序。值小的放大的数,同权值的,越靠前面的放越大的数才符合最长上升子序列的值。

技术分享图片
#include <bits/stdc++.h>

const int N = 1e5 + 7;

struct In {
    int pos, val;
    bool operator < (const In &rhs) const {
        if (val == rhs.val) return pos < rhs.pos;
        return val < rhs.val;
    }
} in[N];

int ans[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &in[i].val);
        in[i].pos = i;
    }
    std::sort(in + 1, in + 1 + n);
    for (int i = 1; i <= n; i++)
        ans[in[i].pos] = n - i + 1;
    for (int i = 1; i <= n; i++)
        printf("%d%c", ans[i], " \n"[i == n]);
    return 0;
}
View Code

 

L - Divide and Conquer

总边数是 $4(n-1)$,至少存在一个点的度数不超过 $3$,那么答案肯定不超过 $3$,并且有一棵树的只割去一条边。

枚举 $A$ 树中每一条边作为割边,在 $B$ 树中这条边连接的两个端点在 $A$ 树中不在一个连通块中,那么这条边需要割掉。

树上启发式合并解决。

技术分享图片
#include <bits/stdc++.h>
#define pii pair<int, int>

const int N = 1e5 + 7;

struct Tree {
    std::vector<int> G[N];
    int son[N], sz[N];
    inline void add(int u, int v) {
        G[u].push_back(v);
        G[v].push_back(u);
    }
    void dfs(int u, int fa) {
        sz[u] = 1;
        for (auto v: G[u]) {
            if (v == fa) continue;
            dfs(v, u);
            sz[u] += sz[v];
            if (sz[son[u]] < sz[v]) son[u] = v;
        }
    }
} a, b;

bool skip[N], color[N];
int cur, n;

void cal(int u, const Tree &a) {
    color[u] ^= 1;
    for (auto v: a.G[u])
        if (color[v] != color[u]) cur++;
        else cur--;
}

void edt(int u, int fa, const Tree &a, const Tree &b) {
    cal(u, b);
    for (auto v: a.G[u])
        if (v != fa && !skip[v])
            edt(v, u, a, b);
}

void dfs(int u, int fa, bool keep, const Tree &a, const Tree &b, std::pii &ans) {
    for (auto v: a.G[u]) 
        if (v != fa && v != a.son[u])
            dfs(v, u, 0, a, b, ans);
    if (a.son[u])
        dfs(a.son[u], u, 1, a, b, ans), skip[a.son[u]] = 1;
    edt(u, fa, a, b);
    if (fa) {
        if (cur < ans.first) ans = std::pii(cur, 0);
        if (ans.first == cur) ans.second++;
    }
    if (a.son[u]) skip[a.son[u]] = 0;
    if (!keep)
        edt(u, fa, a, b);
}

std::pii solve(Tree &a, Tree &b) {
    a.dfs(1, 0);
    std::pii ans = std::pii(n, 0);
    dfs(1, 0, 0, a, b, ans);
    ans.first++;
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        a.add(u, v);
    }
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        b.add(u, v);
    }
    auto ans = solve(a, b);
    if (ans.first == 2) 
        return 0 * printf("%d %d\n", 2, ans.second);
    cur = 0;
    auto res = solve(b, a);
    cur = 0;
    if (ans.first == 3) cur += ans.second;
    if (res.first == 3) cur += res.second;
    printf("%d %d\n", 3, cur);
    return 0;
}
View Code

 

2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017)

原文:https://www.cnblogs.com/Mrzdtz220/p/11664575.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!