Educational Codeforces Round 17
Educational Codeforces Round 17
https://codeforces.com/contest/762
A. k-th divisor
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n, k;
void get_div (ll x) {
vector<ll> v;
v.push_back (1);
if (x != 1) v.push_back (x);
for (ll i = 2; i*i <= x; i++) {
if (x % i == 0) {
v.push_back (i);
if (i != x / i) {
v.push_back (x / i);
}
}
}
sort (v.begin (), v.end ());
//cout << v.size () << endl;
//for (auto i : v) cout << i << ' '; cout << endl;
if (v.size () < k) cout << -1;
else cout << v[k-1];
}
int main () {
cin >> n >> k;
get_div (n);
}
B. USB vs. PS/2
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a, b, c, n, cnt;
ll ans;
multiset<int> s1, s2;
int main () {
cin >> a >> b >> c >> n;
for (int i = 0; i < n; i++) {
int x;
string s;
cin >> x >> s;
if (s[0] == 'U') s1.insert (x);
else s2.insert (x);
}
while (s1.size () && a > 0) {
cnt ++, ans += *s1.begin ();
s1.erase (s1.begin ()), a --;
}
while (s2.size () && b > 0) {
cnt ++, ans += *s2.begin ();
s2.erase (s2.begin ()), b --;
}
multiset<int> s;
for (auto i : s1) s.insert (i);
for (auto i : s2) s.insert (i);
while (s.size () && c > 0) {
cnt ++, c --;
ans += *s.begin ();
s.erase (s.begin ());
}
cout << cnt << ' ' << ans << endl;
}
C. Two strings
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int posl[N], posr[N], ansr, ansl, n, m;
bool check (int l, int r) { //删掉[l,r]
if (posl[l-1] < posr[r+1]) return true;
return false;
}
int main () {
string a, b;
cin >> a >> b;
n = a.size (), m = b.size ();
a = ' ' + a, b = ' ' + b;
ansl = 0, ansr = m + 1;
for (int i = 0; i <= m + 1; i++) posl[i] = n + 1;
//预处理匹配
for (int i = 1, j = 1; i <= m && j <= n; j++) {
if (a[j] == b[i]) posl[i] = j, i ++;
}
for (int i = m, j = n; i >= 1 && j >= 1; j--) {
if (a[j] == b[i]) posr[i] = j, i --;
}
//for (int i = 1; i <= m; i++) cout << posl[i] << ' '; cout << endl;
//for (int i = 1; i <= m; i++) cout << posr[i] << ' '; cout << endl;
if (posl[1] == n + 1 && posr[m] == 0) {
cout << '-';
return 0;
}
//if (posl[1] == n + 1) { //删前缀
for (int i = 1; i <= m; i++) {
if (posr[i] != 0) {
ansl = 1, ansr = i - 1;
break;
}
}
//}
//else if (posr[m] == 0) { //删后缀
for (int i = m; i >= 1; i--) {
if (posl[i] != n + 1) {
if (m - i - 1 < ansr - ansl) ansl = i + 1, ansr = m;
break;
}
}
//}
//else {
//二分枚举
for (int l = 1; l <= m; l++) {
int tl = l, tr = m;
while (tl < tr) {
int mid = tl + tr >> 1;
if (check (l, mid)) tr = mid;
else tl = mid + 1;
//cout << l << ' ' << tr << endl;
}
//cout << endl;
if (check (l, tr)) {
int r = tr;
if (ansr - ansl > r - l) ansl = l, ansr = r;
}
}
//}
if (!ansl) cout << '-';
else {
//cout << ansl << ' ' << ansr << endl;
for (int i = 1; i < ansl; i++) cout << b[i];
for (int i = ansr + 1; i <= m; i++) cout << b[i];
}
}
//题意: 把b删掉一段连续的后,使其成为a的子序列,输出删去后满足条件的最长b
//优化枚举: 找到合法方案后, 删除更多依旧合法, 故枚举左端点, 二分右端点
//优化匹配: (核心: 每个b都有在a中对应的位置, 因为a不变所以可以记录位置)
//posl[i]: b中[1,i]的字符匹配到a里, 第i个元素在a中对应的位置(前缀匹配)
//posr[i]: b中[i,lenb]的字符匹配到a里, 第i个元素在a中对应的位置(后缀匹配)
//则匹配等价于check是否满足posl[l-1] < posr[r+1]即可
D. Maximum path
嗨难想的状态
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5, inf = -1e18;
int ans = -1e18;
int f[N][5]; //对应第i列的5种情况
int a[5][N], n, m;
int s1, s2, s3, s12, s23, s123;
signed main () {
cin >> m;
n = 3;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
for (int k = 0; k < 5; k++) f[j][k] = inf;
}
}
s1 = a[1][1], s12 = a[1][1] + a[2][1], s123 = s12 + a[3][1];
f[1][0] = s1, f[1][1] = s12, f[1][2] = f[1][3] = s123;
for (int i = 2; i <= m; i++) {
int st0 = f[i-1][0], st1 = f[i-1][1], st2 = f[i-1][2], st3 = f[i-1][3], st4 = f[i-1][4];
s1 = a[1][i], s2 = a[2][i], s3 = a[3][i], s12 = s1 + s2, s23 = s2 + s3, s123 = s1 + s23;
f[i][0] = max ({st0 + s1, st1 + s12, st2 + s123, st4 + s123});
f[i][1] = max ({st0 + s12, st1 + s2, st2 + s23});
f[i][2] = max ({st0 + s123, st1 + s23, st2 + s3, st3 + s123});
f[i][3] = st0 + s123;
f[i][4] = st2 + s123;
}
cout << max (f[m][2], f[m][3]) << endl;
}
//偶数的时候可以被不返回的路径代替
//奇数的时候往左可以转化为,每次只往回走一格,可以枚举返回的位置,转化为子问题
//设五个状态