10.14訓練賽
阿新 • • 發佈:2021-10-22
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");
}
}