10.14训练赛

A. CodeForces 1526D

由D题可以知道交换需要的次数就是目标字符串相对于原字符串的逆序对个数,

想让逆序对个数尽可能多那么相同字符要连在一起,所以只需要枚举全排列即可。

#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
using namespace std;
long long t, n, m, ans, f;

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> t;
    while (t--) {
        string s, p = "ANOT", t;
        cin >> s;
        int cnt[100]{};
        for (int c : s) ++cnt[c];
        ans = -1;
        do {
            n = 0;
            string cur = s, T;
            for (char c : p) {
                f = 0;
                T = "";
                for (char x : cur) {
                    if (x == c)
                        n += f;
                    else
                        ++f, T += x;
                }
                cur = T;
            }
            if (n > ans)
                ans = n, t = p;
        } while (next_permutation(&p[0], &p[4]));
        fu(i, 0, 3) while (cnt[t[i]]--) cout << t[i];
        cout << '\n';
    }
}

B. CodeForces 1526C2

显然的反悔贪心。

#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll N = 3e5 + 1, M = 31621;
ll t, n, m, k, a, b, c, d, e, f, l, r, ans;
ll x[N], w[N], y[N], z[N];

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    multiset<ll> s;
    fu(i, 1, n) {
        cin >> a;
        b += a;
        if (a < 0)
            s.insert(a);
        if (b < 0)
            b -= *s.begin(), s.erase(s.begin()), ++c;
    }
    cout << n - c;
}

C. CodeForces 1526E

考虑后缀数组的定义,如果\(rk[sa[i] + 1] > rk[sa[i + 1] + 1]\)那么\(s[i] < s[i + 1]\),

否则\(s[i] <= s[i + 1]\),遍历一遍就得到了所有相邻字符间的关系,剩下就是一个组合数学

的问题,可以考虑对应的差分数组用隔板法解决。

#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
typedef long long ll;
typedef long double ld;
const ll N = 2e5 + 1, M = 998244353;
ll t, n, m, k, ans;
ll a, b = 1, c, d, e = -1e7;
ll x[N], y[N], z[N], v[N];
ll sa[N], rk[N];
string s;

inline ll inv(ll x) {
    return x ^ 1 ? (M - M / x) * inv(M % x) % M : 1;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> k;
    fu(i, 1, n) cin >> sa[i], rk[sa[i]] = i;
    c = ans = 1, m = n;
    fu(i, 1, n - 1) c += rk[sa[i] + 1] > rk[sa[i + 1] + 1], m = m * i % M;
    a = n + k - c;
    fu(i, 0, n - 1) ans = ans * (a - i) % M;
    cout << ans * inv(m) % M;
}

D. CodeForces 1430E

将原串每个字符替换成其在目标串中的位置,就得到了一个排列,每次交换相邻元素可以
减少一个这个排列的逆序对,而我们的目标是清空逆序对,所以统计逆序对个数即可。

def cal(l, r):
    if(l == r):
        return
    m = l + r >> 1
    cal(l, m), cal(m + 1, r)
    l1 = l; l2 = m + 1; c = l
    global ans
    while l1 <= m and l2 <= r:
        if a[l1] < a[l2]:
            b[c] = a[l1]
            l1 += 1
            ans += l2 - m - 1
        else:
            b[c] = a[l2]
            l2 += 1
        c += 1
    while l1 <= m:
        b[c] = a[l1]
        ans += l2 - m - 1
        l1 += 1
        c += 1
    while l2 <= r:
        b[c] = a[l2]
        l2 += 1
        c += 1
    a[l : r + 1] = b[l : r + 1]

n = int(input())
s = input()
v = [[] for i in range(26)]
p = [0] * 26
for i in range(n):
    v[ord(s[i]) - 97].append(i)

a = [0] * n; b = [0] * n
for i in range(n - 1, -1, -1):
    c = ord(s[i]) - 97
    a[n - 1 - i] = v[c][p[c]]
    p[c] += 1
ans = 0
cal(0, n - 1)
print(ans)

E. CodeForces 1428D

贪心构造。

input()
c2, c3, ans = [], [], []
k = [c2, c3]
for i, x in enumerate(map(int, input().split()), 1):
    if x == 1:
        if c2:
            ans += [(c2.pop(), i)]
        elif c3:
            ans += [(c3.pop(), i), (i, i)]
        else:
            ans += [(i, i)]
    elif x != 0:
        ans += [(i, i)]
        if c3:
            ans += [(c3.pop(), i)]
        k[x-2] += [i]
if c2 or c3:
    print(-1)
else:
    print(len(ans))
    for i in ans:
        print(*i)

F. HDU 4871

最短路建树然后点分治。

#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
const ll N = 1e5 + 10;
ll t, n, m, k, rt, mxd, mdc;
ll dis[N], c[N]{0, 1}, d[N];
ll pre[N], sz[N], mx[N]{N};
bool vis[N];
vector<pll> g[N], G[N];

void get_rt(ll u, ll f, ll tot) {
    sz[u] = 1, mx[u] = 0;
    for (auto i : g[u]) {
        ll v = i.first;
        if (v ^ f && !vis[v]) {
            get_rt(v, u, tot);
            sz[u] += sz[v];
            mx(mx[u], sz[v]);
        }
    }
    mx(mx[u], tot - sz[u]);
    if (mx[u] < mx[rt])
        rt = u;
}

void upd(ll u, ll f, ll dis, ll dep, bool F) {
    if (dep == k)
        return;
    if (F) { // 当前子树所有节点的贡献计算完后再更新
        // 每次只计算经过根节点的路径,所以把之前子树中每个dep对应最大dis和数量存起来
        if (dis > d[dep + 1])
            d[dep + 1] = dis, c[dep + 1] = 1;
        else if (dis == d[dep + 1])
            ++c[dep + 1];
    } else if (c[k - dep]) {
        if (dis + d[k - dep] > mxd)
            mxd = dis + d[k - dep], mdc = c[k - dep];
        else if (dis + d[k - dep] == mxd)
            mdc += c[k - dep];
    }
    for (auto i : g[u]) {
        ll v = i.first, w = i.second;
        if (v ^ f && !vis[v])
            upd(v, u, dis + w, dep + 1, F);
    }
}

void go(ll u) {
    vis[u] = 1;
    // d[1] = 0, c[1] = 1
    memset(d + 2, 0, k - 2 << 3);
    memset(c + 2, 0, k - 2 << 3);
    for (auto i : g[u]) {
        ll v = i.first, w = i.second;
        if (!vis[v])
            upd(v, u, w, 1, 0), upd(v, u, w, 1, 1);
    }
    for (auto i : g[u]) {
        ll v = i.first;
        if (!vis[v])
            rt = 0, get_rt(v, 0, sz[v]), go(rt);
    }
}

inline void dij() {
    memset(dis + 1, 60, n * 8), dis[1] = 0;
    priority_queue<pll, vector<pll>, greater<pll>> q;
    q.emplace(0, 1);
    ll u, v, d;
    while (q.size()) {
        pll t = q.top();
        d = t.first, u = t.second, q.pop();
        if (d > dis[u])
            continue;
        if (v = pre[u]) {
            g[v].emplace_back(u, d - dis[v]);
            g[u].emplace_back(v, d - dis[v]);
        }
        for (auto i : G[u]) {
            ll v = i.first, w = i.second, nxd = dis[u] + w;
            if (nxd < dis[v] || nxd == dis[v] && u < pre[v])
                q.emplace(nxd, v), pre[v] = u, dis[v] = nxd;
        }
    }
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> t;
    ll u, v, w;
    while (t--) {
        cin >> n >> m >> k;
        fu(i, 1, n) g[i].clear(), G[i].clear();
        memset(vis + 1, 0, n);
        fu(i, 1, m) {
            cin >> u >> v >> w;
            G[u].emplace_back(v, w);
            G[v].emplace_back(u, w);
        }
        dij();
        rt = mxd = mdc = 0, get_rt(1, 0, n), go(rt);
        cout << mxd << ' ' << mdc << '\n';
    }
}

G. CodeForces 1426B

900分的签到题,然鹅我当初还被hack了。

#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
using namespace std;
bool f[101], f1[101];

int main() {
    int t, n, m, a, b, c, d;
    scanf("%d", &t);
    while (t--) {
        memset(f, 0, sizeof f);
        memset(f1, 0, sizeof f1);
        bool flag = 0;
        scanf("%d%d", &n, &m);
        fu(i, 1, n) {
            scanf("%d%d%d%d", &a, &b, &c, &d);
            falg |= b == c;
        }
        printf("%s\n", m & 1 || !flag ? "NO" : "YES");
    }
}
上一篇:膜你赛 2021.10.18


下一篇:【ybt金牌导航8-6-4】原根数量