您的位置:首页 > 其它

【CodeForces】CodeForces Round #465 (Div. 2) 题解

2018-02-23 20:13 661 查看
【比赛链接】
点击打开链接

【题解链接】
点击打开链接

【A】Fafa and his Company
【思路要点】
求\(N\)的因数个数减1,乱做就行。
时间复杂度\(O(N)\)或\(O(\sqrt{N})\)
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5005;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int main() {
int n, ans = 0; read(n);
for (int i = 1; i <= n - 1; i++)
if (n % i == 0) ans++;
printf("%d\n", ans);
return 0;
}

【B】Fafa and the Gates
【思路要点】
按照题意模拟过程即可。
时间复杂度\(O(N)\)。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
char s[MAXN];
int main() {
int n; read(n);
scanf("%s", s + 1);
int x = 0, y = 0, ans = 0;
for (int i = 1; i <= n; i++) {
if (x == y && s[i] == s[i - 1]) ans++;
if (s[i] == 'U') y++;
else x++;
}
cout << ans << endl;
return 0;
}

【C】Fifa and Fafa
【思路要点】
将圆心设置在两个点的连线上,使得圆经过\((x_2,y_2)\),包含\((x_1,y_1)\),且与大圆相切。
注意特判点在圆外和两点重合的情况。
时间复杂度\(O(1)\)。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5005;
const long double eps = 1e-10;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int main() {
long double R, X1, Y1, X2, Y2;
read(R), read(X1), read(Y1), read(X2), read(Y2);
long double dist = sqrt((X1 - X2) * (X1 - X2) + (Y1 - Y2) * (Y1 - Y2));
if (dist >= R - eps) {
printf("%.10Lf %.10Lf %.10Lf\n", X1, Y1, R - eps);
return 0;
}
if (dist <= eps) {
printf("%.10Lf %.10Lf %.10Lf\n", X1 + R / 2, Y1, R / 2 - eps);
return 0;
}
long double ans = (R + dist) / 2 - eps, dx, dy;
dx = X1 - X2, dy = Y1 - Y2;
printf("%.10Lf %.10Lf %.10Lf\n", X2 + dx / dist * (dist + R) / 2, Y2 + dy / dist * (dist + R) / 2, ans);
return 0;
}

【D】Fafa and Ancient Alphabet
【思路要点】
逐位确定大小关系,将\(S_1\)大于\(S_2\)的概率加入答案,保留\(S_1\)等于\(S_2\)的概率到下一位。
时间复杂度\(O(N)\)。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const int P = 1e9 + 7;
const int inv2 = (P + 1) / 2;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int a[MAXN], b[MAXN];
long long power(long long x, long long y) {
if (y == 0) return 1;
long long tmp = power(x, y / 2);
if (y % 2 == 0) return tmp * tmp % P;
else return tmp * tmp % P * x % P;
}
int main() {
int n, m;
read(n), read(m);
for (int i = 1; i <= n; i++)
read(a[i]);
for (int i = 1; i <= n; i++)
read(b[i]);
long long ans = 0, now = 1, inv = power(m, P - 2);
for (int i = 1; i <= n; i++) {
if (a[i] != 0 && b[i] != 0) {
if (a[i] > b[i]) {
ans += now;
ans %= P;
break;
}
if (a[i] < b[i]) break;
continue;
}
now = now * inv % P;
if (a[i] != 0 && b[i] == 0) {
ans += now * (a[i] - 1);
ans %= P;
continue;
}
if (a[i] == 0 && b[i] != 0) {
ans += now * (m - b[i]);
ans %= P;
continue;
}
ans += now * (m - 1) % P * inv2;
ans %= P;
}
cout << ans << endl;
return 0;
}

【E】Fafa and Ancient Mathematics
【思路要点】
我们可以将问题转化成如下的形式:有一棵二叉树,它的叶子节点上是数,非叶节点上需要填入一个符号,使得其先下后上地计算得到的值最大化。
考虑DP,记录\(Max_{i,j}\)和\(Min_{i,j}\)表示在第\(i\)个节点子树中填入\(j\)个加号/减号,其他的填减号/加号,可以得到的最大/最小得数。
转移较为显然,枚举根节点的符号以及左右子树符号的分配即可。
状态的第二维记录输入时较少的一种符号。
时间复杂度\(O(|E|*Min^2(P,M))\)。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
const int MAXM = 105;
const int INF = 1e7;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
char s[MAXN];
int size, p, m;
int sum[MAXN], lc[MAXN], rc[MAXN];
int Max[MAXN][MAXM];
int Min[MAXN][MAXM];
int split(int l, int r) {
int cnt = 0;
for (int i = l; i <= r; i++) {
if (s[i] == '(') cnt++;
if (s[i] == ')') cnt--;
if (s[i] == '?' && cnt == 0) return i;
}
return -1;
}
void chkmax(int &x, int y) {x = max(x, y); }
void chkmin(int &x, int y) {x = min(x, y); }
void workp(int pos, int l, int r) {
if (l == r) {
Max[pos][0] = Min[pos][0] = s[l] - '0';
return;
}
int mid = split(l + 1, r - 1);
lc[pos] = ++size;
rc[pos] = ++size;
workp(lc[pos], l + 1, mid - 1);
workp(rc[pos], mid + 1, r - 1);
sum[pos] = 1 + sum[lc[pos]] + sum[rc[pos]];
for (int i = 0; i <= p && i <= sum[pos]; i++) {
Max[pos][i] = -INF; Min[pos][i] = INF;
for (int j = 0; j <= i && j <= sum[lc[pos]]; j++) {
int k = i - j;
if (k > sum[rc[pos]]) continue;
chkmax(Max[pos][i], Max[lc[pos]][j] - Min[rc[pos]][k]);
chkmin(Min[pos][i], Min[lc[pos]][j] - Max[rc[pos]][k]);
}
if (i == 0) continue;
for (int j = 0; j <= i - 1 && j <= sum[lc[pos]]; j++) {
int k = i - j - 1;
if (k > sum[rc[pos]]) continue;
chkmax(Max[pos][i], Max[lc[pos]][j] + Max[rc[pos]][k]);
chkmin(Min[pos][i], Min[lc[pos]][j] + Min[rc[pos]][k]);
}
}
}
void workm(int pos, int l, int r) {
if (l == r) {
Max[pos][0] = Min[pos][0] = s[l] - '0';
return;
}
int mid = split(l + 1, r - 1);
lc[pos] = ++size;
rc[pos] = ++size;
workm(lc[pos], l + 1, mid - 1);
workm(rc[pos], mid + 1, r - 1);
sum[pos] = 1 + sum[lc[pos]] + sum[rc[pos]];
for (int i = 0; i <= m && i <= sum[pos]; i++) {
Max[pos][i] = -INF; Min[pos][i] = INF;
for (int j = 0; j <= i && j <= sum[lc[pos]]; j++) {
int k = i - j;
if (k > sum[rc[pos]]) continue;
chkmax(Max[pos][i], Max[lc[pos]][j] + Max[rc[pos]][k]);
chkmin(Min[pos][i], Min[lc[pos]][j] + Min[rc[pos]][k]);
}
if (i == 0) continue;
for (int j = 0; j <= i - 1 && j <= sum[lc[pos]]; j++) {
int k = i - j - 1;
if (k > sum[rc[pos]]) continue;
chkmax(Max[pos][i], Max[lc[pos]][j] - Min[rc[pos]][k]);
chkmin(Min[pos][i], Min[lc[pos]][j] - Max[rc[pos]][k]);
}
}
}
int main() {
scanf("%s", s + 1);
read(p), read(m);
if (p <= m) {
workp(++size, 1, strlen(s + 1));
printf("%d\n", Max[1][p]);
} else {
workm(++size, 1, strlen(s + 1));
printf("%d\n", Max[1][m]);
}
return 0;
}

【F】Fafa and Array
【思路要点】
令当前数组相邻值的差的绝对值之和为\(sum\),对于询问操作,答案不会超过\(sum+2*x\)。
当且仅当区间中存在一个大于等于左右两边的数的数,答案等于\(sum+2*x\)。
否则,区间一定是由至多两段递增或递减的数组成的,我们找到断点,分别处理断点和两侧。
若询问在一段递增或递减的数上,那么我们应该操作在相差最小的一对相邻的数上。
将数组差分,用线段树维护区间最大、最小值,以及一些有关断点的信息,实现上述过程。
本题笔者的做法实现较为困难,代码可读性较低。
时间复杂度\(O(QLogN)\)。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
struct info {int cnt, pos; };
info operator + (info a, info b) {
info ans;
ans.cnt = a.cnt + b.cnt;
if (ans.cnt == 1) ans.pos = a.pos + b.pos;
else if (a.pos) ans.pos = a.pos; else ans.pos = b.pos;
return ans;
}
struct SegmentTree {
struct Node{
int lc, rc;
info top, low;
long long Min, Max;
} a[MAXN * 2];
int n, size, root;
void update(int root) {
int lc = a[root].lc, rc = a[root].rc;
a[root].Min = min(a[lc].Min, a[rc].Min);
a[root].Max = max(a[lc].Max, a[rc].Max);
a[root].top = a[lc].top + a[rc].top;
a[root].low = a[lc].low + a[rc].low;
}
void build(int &root, int l, int r, long long *val) {
root = ++size;
if (l == r) {
a[root].Min = a[root].Max = val[l];
if (l != n) {
bool tlow = val[l] <= 0 && val[l + 1] >= 0;
a[root].low = (info) {tlow, l * tlow};
bool ttop = val[l] >= 0 && val[l + 1] <= 0;
a[root].top = (info) {ttop, l * ttop};
} else {
a[root].low = (info) {0, 0};
a[root].top = (info) {0, 0};
}
return;
}
int mid = (l + r) / 2;
build(a[root].lc, l, mid, val);
build(a[root].rc, mid + 1, r, val);
update(root);
}
void init(int x, long long *val) {
n = x;
root = size = 0;
build(root, 1, n, val);
}
void modify(int root, int l, int r, int pos, long long val, bool ttop, bool tlow) {
if (l == r) {
a[root].Min = a[root].Max = val;
a[root].top = (info) {ttop, l * ttop};
a[root].low = (info) {tlow, l * tlow};
return;
}
int mid = (l + r) / 2;
if (mid >= pos) modify(a[root].lc, l, mid, pos, val, ttop, tlow);
else modify(a[root].rc, mid + 1, r, pos, val, ttop, tlow);
update(root);
}
long long queryval(int root, int l, int r, int pos) {
if (l == r) return a[root].Max;
int mid = (l + r) / 2;
if (mid >= pos) return queryval(a[root].lc, l, mid, pos);
else return queryval(a[root].rc, mid + 1, r, pos);
}
long long queryval(int pos) {
return queryval(root, 1, n, pos);
}
void Modify(int pos, long long val) {
if (pos != n) {
long long tmp = queryval(root, 1, n, pos + 1);
bool ttop = false, tlow = false;
if (val <= 0 && tmp >= 0) tlow = true;
if (val >= 0 && tmp <= 0) ttop = true;
modify(root, 1, n, pos, val, ttop, tlow);
} else modify(root, 1, n, pos, val, false, false);
}
void modify(int pos, long long val) {
if (pos != n) {
long long tmp = queryval(root, 1, n, pos + 1);
bool ttop = false, tlow = false;
if (val <= 0 && tmp >= 0) tlow = true;
if (val >= 0 && tmp <= 0) ttop = true;
modify(root, 1, n, pos, val, ttop, tlow);
} else modify(root, 1, n, pos, val, false, false);
if (pos != 1) Modify(pos - 1, queryval(root, 1, n, pos - 1));
}
info querylow(int root, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[root].low;
int mid = (l + r) / 2;
info ans = (info) {0, 0};
if (mid >= ql) ans = ans + querylow(a[root].lc, l, mid, ql, min(qr, mid));
if (mid + 1 <= qr) ans = ans + querylow(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);
return ans;
}
info querylow(int l, int r) {
return querylow(root, 1, n, l, r);
}
info querytop(int root, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[root].top;
int mid = (l + r) / 2;
info ans = (info) {0, 0};
if (mid >= ql) ans = ans + querytop(a[root].lc, l, mid, ql, min(qr, mid));
if (mid + 1 <= qr) ans = ans + querytop(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);
return ans;
}
info querytop(int l, int r) {
return querytop(root, 1, n, l, r);
}
long long querymax(int root, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[root].Max;
int mid = (l + r) / 2;
long long ans = -LLONG_MAX;
if (mid >= ql) ans = max(ans, querymax(a[root].lc, l, mid, ql, min(qr, mid)));
if (mid + 1 <= qr) ans = max(ans, querymax(a[root].rc, mid + 1, r, max(mid + 1, ql), qr));
return ans;
}
long long querymax(int l, int r) {
return querymax(root, 1, n, l, r);
}
long long querymin(int root, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[root].Min;
int mid = (l + r) / 2;
long long ans = LLONG_MAX;
if (mid >= ql) ans = min(ans, querymin(a[root].lc, l, mid, ql, min(qr, mid)));
if (mid + 1 <= qr) ans = min(ans, querymin(a[root].rc, mid + 1, r, max(mid + 1, ql), qr));
return ans;
}
long long querymin(int l, int r) {
return querymin(root, 1, n, l, r);
}
} ST;
int n, q;
long long sum, a[MAXN];
void add(int l, int r, int d) {
if (l != 1) sum -= abs(a[l]);
sum -= abs(a[r + 1]);
a[l] += d, ST.modify(l, a[l]);
if (r != n) a[r + 1] -= d, ST.modify(r + 1, a[r + 1]);
if (l != 1) sum += abs(a[l]);
sum += abs(a[r + 1]);
}
void judge(long long &ans, int x, int l, int r) {
if (l > r) return;
long long tmp = sum + 2 * x;
if (ST.queryval(l) <= 0) ans = max(ans, tmp - 2 * min(x * 1ll, abs(ST.querymax(l, r))));
else ans = max(ans, tmp - 2 * min(x * 1ll, abs(ST.querymin(l, r))));
}
int main() {
read(n);
for (int i = 1; i <= n; i++)
read(a[i]);
for (int i = n; i >= 2; i--) {
a[i] -= a[i - 1];
sum += abs(a[i]);
}
ST.init(n, a);
read(q);
while (q--) {
int opt, l, r, x;
read(opt), read(l), read(r), read(x);
if (opt == 2) add(l, r, x);
else {
long long ans = 0;
add(l, l, x); ans = max(ans, sum); add(l, l, -x);
add(r, r, x); ans = max(ans, sum); add(r, r, -x);
if (r - l <= 1) {
writeln(ans);
continue;
}
add(l + 1, l + 1, x); ans = max(ans, sum); add(l + 1, l + 1, -x);
add(r - 1, r - 1, x); ans = max(ans, sum); add(r - 1, r - 1, -x);
info tmp = ST.querylow(l + 1, r);
info tnp = ST.querytop(l + 1, r);
if (tnp.cnt != 0) {
writeln(sum + 2 * x);
continue;
}
if (tmp.cnt != 0) {
add(tmp.pos, tmp.pos, x); ans = max(ans, sum); add(tmp.pos, tmp.pos, -x);
if (tmp.pos != l) add(tmp.pos - 1, tmp.pos - 1, x), ans = max(ans, sum), add(tmp.pos - 1, tmp.pos - 1, -x);
if (tmp.pos != r) add(tmp.pos + 1, tmp.pos + 1, x), ans = max(ans, sum), add(tmp.pos + 1, tmp.pos + 1, -x);
judge(ans, x, l + 2, tmp.pos - 1);
judge(ans, x, tmp.pos + 2, r - 1);
} else judge(ans, x, l + 2, r - 1);
writeln(ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: