Educational Codeforces Round 161
A. Tricky Template
void solve(int cs) {
int n;
cin >> n;
string a, b, c;
cin >> a >> b >> c;
for (int i = 0; i < n; i++) {
if (a[i] != c[i] && b[i] != c[i]) {
cout << "YES\n";
return;
}
}
cout << "NO\n";
}
B. Forming Triangles
根据边长特性只能选择两个相同的大边和一条小于等于他的边构成等腰/等边三角形,从大到小排好序后求组合数即可
bool cmp(int a, int b) {
return a > b;
}
void solve(int cs) {
int n;
cin >> n;
VI a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int ans = 0, cnt = 1;
sort(a.begin(), a.end(), cmp);
for (int i = 1; i < n; i++) {
cnt = 1;
while (a[i] == a[i - 1] && i < n) {
cnt++;
i++;
}
if (cnt == 1) continue;
if (cnt == 2) {
ans += ((cnt * (cnt - 1) / 2) * (n - i));//(comb(cnt, 2) * (n - i))------((cnt * (cnt - 1) / 2) * (n - i))
continue;
}
ans += ((cnt * (cnt - 1) * (cnt - 2) / 6) + ((cnt * (cnt - 1) / 2) * (n - i)));//(comb(cnt, 3) + comb(cnt, 2) * (n - i))------((cnt * (cnt - 1) * (cnt - 2) / 6) + ((cnt * (cnt - 1) / 2) * (n - i)))
}
cout << ans << endl;
}
C. Closest Cities
记一下前缀和后缀和即可
struct Node {
int x, l, r;
};
void solve(int cs) {
int n;
cin >> n;
vector<Node> a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i].x;
a[1].r = 1;a[n].l = 1;
for (int i = 2; i < n; i++) {
if (a[i].x - a[i - 1].x > a[i + 1].x - a[i].x) a[i].r = 1;
else a[i].l = 1;
}
VI sum1(n + 1);
VI sum2(n + 1);
for (int i = 2; i <= n; i++) {
sum1[i] = sum1[i - 1] + (a[i - 1].r == 1 ? 1 : a[i].x - a[i - 1].x);
}
for (int i = n - 1; i > 0; i--) {
sum2[i] = sum2[i + 1] + (a[i + 1].l == 1 ? 1 : a[i + 1].x - a[i].x);
}
int m;
cin >> m;
while (m--) {
int x, y;
cin >> x >> y;
if (x < y) {
cout << sum1[y] - sum1[x] << endl;
}
else {
cout << sum2[y] - sum2[x] << endl;
}
}
}
D. Berserk Monsters
按照题意用链表储存怪的相对位置关系,用set储存每一轮每一只怪防御力与收到伤害的差,然后按题意模拟即可
void solve(int cs) {
int n;
cin >> n;
VI a(n + 1);
VI d(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> d[i];
VI r(n + 1);
VI l(n + 1);
for (int i = 1; i <= n; i++) {
r[i] = i + 1;
l[i] = i - 1;
}
r[n] = 0;
set<pii > s;
for (int i = 1; i <= n; i++) s.insert(make_pair(d[i] - a[l[i]] - a[r[i]], i));
VI v(n + 1);
VI ans(n + 1);
for (int i = 1; i <= n; i++) {
VI ddd;
while(!s.empty() && s.begin()->first < 0) {
ddd.pb(s.begin()->second);
v[s.begin()->second] = 1;
s.erase(s.begin());
}
if (ddd.empty()) break;
ans[i] = ddd.size();
for (auto x : ddd) {
if (l[x] && !v[l[x]]) s.erase(make_pair(d[l[x]] - a[l[l[x]]] - a[r[l[x]]], l[x]));
if (r[x] && !v[r[x]]) s.erase(make_pair(d[r[x]] - a[l[r[x]]] - a[r[r[x]]], r[x]));
r[l[x]] = r[x];
l[r[x]] = l[x];
if (l[x] && !v[l[x]]) s.insert(make_pair(d[l[x]] - a[l[l[x]]] - a[r[l[x]]], l[x]));
if (r[x] && !v[r[x]]) s.insert(make_pair(d[r[x]] - a[l[r[x]]] - a[r[r[x]]], r[x]));
}
}
for (int i = 1; i <= n; i++) cout << ans[i] << " ";
cout << endl;
}
E - Increasing Subsequences
x x x个数所组成的递增序列有 2 x 2^x 2x个递增子序列,所以将所给数二进制拆分,首先构造出最高位,然后按照二进制位上数字进行构造
void solve(int cs) {
int x;
cin >> x;
stack<int> st;
while(x) {
st.push(x & 1);
x >>= 1;
}
int cnt = st.size();
VI ans;
for (int i = 1; i < cnt; i++) {
ans.pb(i);
}
st.pop();cnt--;
while(!st.empty()) {
if (st.top()) {
ans.pb(cnt);
}
st.pop();
cnt--;
}
cout << ans.size() << endl;
for (auto i : ans) {
cout << i << " ";
}
cout << endl;
}
F - Replace on Segment
令 d p 1 [ l ] [ r ] [ k ] dp1[l][r][k] dp1[l][r][k]表示把区间 [ l , r ] [l,\ r] [l, r]中所有数变成 k k k的最小操作数,最后答案显然是 min i ∈ [ 1 , x ] { d p 1 [ 1 ] [ n ] [ i ] } \min\limits_{i\in[1,x]} \{dp1[1][n][i]\} i∈[1,x]min{dp1[1][n][i]}
接下来考虑如何进行状态转移,将一个区间全部变成相同的数 k k k有两种方法:
- 直接将区间内所有非 k k k数字全部变成 k k k
- 将区间内所有 k k k全变成非 k k k,然后再通过一次操作将整个区间都变成 k k k,下面的代码中 d p 2 [ l ] [ r ] [ k ] dp2[l][r][k] dp2[l][r][k]表示的就是将区间 [ l , r ] [l,\ r] [l, r]中的所有数变成非 k k k的最小操作数
弄清楚这些之后进行区间dp即可
int dp1[N][N][N], dp2[N][N][N], a[N];
void solve(int cs) {
int n, x;
cin >> n >> x;
for (int i = 1; i <= n; i++) {
cin >> a[i];
for (int j = 1; j <= x; j++) {
dp1[i][i][j] = 1;
dp2[i][i][j] = 0;
}
dp1[i][i][a[i]] = 0;
dp2[i][i][a[i]] = 1;
}
for (int len = 2; len <= n; len++) {
for (int l = 1; l + len - 1 <= n; l++) {
int r = l + len - 1;
for (int k = 1; k <= x; k++) {
dp1[l][r][k] = llinf;
dp2[l][r][k] = llinf;
for (int t = l; t < r; t++) {
dp1[l][r][k] = min(dp1[l][r][k], dp1[l][t][k] + dp1[t + 1][r][k]);
dp2[l][r][k] = min(dp2[l][r][k], dp2[l][t][k] + dp2[t + 1][r][k]);
}
}
VI xl(x + 2);xl[0] = llinf;
VI xr(x + 2);xr[x + 1] = llinf;
for (int k = 1; k <= x; k++) xl[k] = min(dp1[l][r][k], xl[k - 1]);
for (int k = x; k > 0; k--) xr[k] = min(dp1[l][r][k], xr[k + 1]);
for (int k = 1; k <= x; k++){
dp2[l][r][k] = min(dp2[l][r][k], min(xl[k - 1], xr[k + 1]));
dp1[l][r][k] = min(dp1[l][r][k], dp2[l][r][k] + 1);
}
}
}
int ans = llinf;
for (int i = 1; i <= x; i++) {
ans = min(ans, dp1[1][n][i]);
}
cout << ans << endl;
}