[CodeForces]Educational Codeforces Round 28

846A. Curriculum Vitae

题意

给定一个长度为$n$的$01$序列,删掉一些数,使得最终数列中$0$不直接跟在$1$后面,求最长长度。

题解

最终序列一定是$000...111$形式的,$\Theta(n)$枚举最后一个$0$的位置,用前缀和$\Theta(1)$统计一下即可。
时间复杂度:$\Theta(n)$。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 109;
int s[N];
inline int read() {
    int s = 1, a = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
    return s * a;
}
inline int count(int l, int r) {
    return (r >= l ? s[r] - s[l - 1] : 0);
}
int main() {
    int n = read();
    for (int i = 1; i <= n; i++) s[i] = read() + s[i - 1];
    int res = 0;
    for (int i = 0; i <= n; i++) res = max(res, i - count(1, i) + count(i + 1, n));
    return 0 * printf("%d\n", res);
}

846B. Math Show

题意

给定$n$个大题,每个大题都有$k$个小题,第$i$个小题需要花费$t_i$分钟。每做出一小题得$1$分,每做出完整的一个大题多得一分,即$k+1$分。求在$M$分钟完成的最大得分。

题解

先枚举完整做出的大题数,再按每小题花费时间的贪心即可。
时间复杂度:$\Theta(n^2\times k)$。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 59;
int t[N];
inline int read() {
    int s = 1, a = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
    return s * a;
}
int main() {
    int n = read(), k = read(), m = read(), s = 0;
    for (int i = 1; i <= k; i++) t[i] = read(), s += t[i];
    sort(t + 1, t + k + 1);
    ll res = 0;
    for (int i = 0; i <= n; i++) {
        ll tim = i * s, cur = i * (k + 1);
        if (tim > m) break;
        for (int j = 1; j <= k; j++) {
            if (tim + (n - i) * t[j] <= m) tim += (n - i) * t[j], cur += (n - i);
            else {
                while (tim + t[j] <= m) tim += t[j], cur++;
                break;
            }
        }
        res = max(res, cur);
    }
    return 0 * printf("%d\n", res);
}

846C. Four Segments

题意

给定长度为$n$的数列$a_0,a_1,...,a_{n-1}$,定义$sum(l,r)$为区间$[l,r)$内$a_i$的和。求三个数$delim_0,delim_1,delim_2(0\leq delim_0\leq delim_1\leq delim_2
\leq n)$将数列分成四段,使得$res=sum(0,delim_0)-sum(delim_0,delim_1)+sum(delim_1,delim_2)-sum(delim_2,n)$最大。

题解

考虑先枚举$delim_1$定下来,再在区间$[0,delim_1]$和$[delim_1,n]$中分别枚举$delim_0$和$delim_2$,这时只要让$sum(0,d_0)$和$sum(d1,d2)$同时取最大,用前缀和加速即可。
时间复杂度:$\Theta(n^2)$。

代码

#include <bits/stdc++.h>
#define DE(x) cout << x << endl
using namespace std;
typedef long long ll;
const int N = 5009;
int a[N];
ll s[N];
struct Sol {
    int d0, d1, d2;
    ll res;
};
inline int read() {
    int s = 1, a = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
    return s * a;
}
inline ll sum(int l, int r) {
    if (l < 0) return s[r - 1];
    return l <= r ? s[r - 1] - s[l - 1] : 0;
}
int main() {
    int n = read();
    for (int i = 0; i < n; i++) a[i] = read();
    s[0] = a[0];
    for (int i = 1; i < n; i++) s[i] = s[i - 1] + a[i];
    Sol ans; ans.d0 = ans.d1 = ans.d2 = ans.res = 0;
    for (int d1 = 0; d1 <= n; d1++) {
        int d0 = d1, d2 = d1;
        for (int j = 0; j <= d1; j++) if (sum(0, j) > sum(0, d0)) d0 = j;
        for (int j = d1; j <= n; j++) if (sum(d1, j) > sum(d1, d2)) d2 = j;
        ll res = sum(0, d0) - sum(d0, d1) + sum(d1, d2) - sum(d2, n);
        if (res > ans.res) ans.res = res, ans.d0 = d0, ans.d1 = d1, ans.d2 = d2;
    }
    return 0 * printf("%d %d %d\n", ans.d0, ans.d1, ans.d2);
}

846D. Monitor

题意

给定一$n\times m$个的点阵,其中有$q$个点$(x_i,y_i)$会在$t_i$时刻变成坏点。求最少何时,存在一个$k\times k$的点阵全是坏点。

题解

二分时间,单调性显然,用二维前缀和判断是否全是坏点即可。
时间复杂度:$\Theta(n^2\times \log q)$。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 509;
int n, m, k, q, x[N*N], y[N*N], t[N*N], s[N][N];
inline int read() {
    int s = 1, a = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
    return s * a;
}
inline bool broke(int mid) {
    memset(s, 0, sizeof(s));
    for (int i = 1; i <= q; i++) if (t[i] <= mid) s[ x[i] ][ y[i] ] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }
    }
    for (int i = k; i <= n; i++) {
        for (int j = k; j <= m; j++) {
            if (s[i][j] - s[i - k][j] - s[i][j - k] + s[i - k][j - k] == k * k) return true;
        }
    }
    return false;
}
int main() {
    n = read(), m = read(), k = read(), q = read();
    for (int i = 1; i <= q; i++) x[i] = read(), y[i] = read(), t[i] = read(), t[0] = max(t[0], t[i]);
    int l = -1, r = t[0] + 1, res = -1;
    while (l + 1 < r) {
        int mid = (l + r) >> 1;
        if (broke(mid)) r = mid, res = r; else l = mid;
    }
    return 0 * printf("%d\n", res);
}

846E. Chemistry in Berland

题意

给定$n$个物品,现各有$b_i$千克,各需要$a_i$千克。其中$k_i$千克的$x_i$物品可以转化成$1$千克的$i$物品,$1$千克的$i$物品可以转化成$1$千克的$x_i$物品。判断能否通过转化使得$n$种物品都满足需求。

题解

树形$DP$。按着题目所述转化条件转移状态即可。注意数据范围。
时间复杂度:$\Theta(n)$。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
const int N = 1e5+9;
ll sum, a[N], b[N], x[N], k[N];
vector<pll> g[N];
bool flag = 1;
inline ll read() {
    ll s = 1, a = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
    return s * a;
}
inline void dfs(int u) {
    for (auto e : g[u]) {
        int k = e.first, v = e.second;
        dfs(v);
        if (b[v] > 0) b[u] += b[v];
        else {
            double w = 1.0 * b[v] * k;
            if (b[u] + w < -sum) flag = 0;
            b[u] += b[v] * k;
        }
    }
}
int main() {
    int n = read();
    for (int i = 1; i <= n; i++) b[i] = read(), sum += b[i];
    for (int i = 1; i <= n; i++) a[i] = read(), b[i] -= a[i];
    for (int i = 2; i <= n; i++) {
        int x = read(), k = read();
        g[x].push_back(make_pair(k, i));
    }
    dfs(1);
    return 0 * puts(b[1] >= 0 ? "YES" : "NO");
}

846F. Random Query

题意

给定$n$个正整数$a_i$,每次随机地选择两个数$l,r$(若$l>r$,则交换两者),定义$(l,r)$的$value$为$a_l,a_{l+1},...,a_r$中不同的数的个数。求$value$的期望。

题解

我们考虑计算$a_l,a_{l+1},...,a_r$中每个数第一次出现的位置。记$pre[i]$表示$i$之前与$a_i$相等的最近的一个数的位置,则$a_i$能对所有$l\in (pre[i],i],r\in [i,n]$的所有区间产生$1$个贡献。
故所求期望为$res=\frac{2*\sum_{i=1}{n}{(i-pre[i])(n-i+1)}-n}{n2}$。
时间复杂度:$\Theta(n)$。

代码


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+9;
int a[N], pos[N], pre[N];
inline int read() {
    int s = 1, a = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {a = a * 10 + ch - '0'; ch = getchar();}
    return s * a;
}
int main() {
    int n = read();
    for (int i = 1; i <= n; i++) a[i] = read(), pre[i] = pos[ a[i] ], pos[ a[i] ] = i;
    ll res = 0;
    for (int i = 1; i <= n; i++) res += 1ll * (i - pre[i]) * (n - i + 1);
    res = res * 2 - n;
    return 0 * printf("%.6lf\n", 1.0 *  res / (1ll * n * n));
}
posted @ 2017-09-08 19:09  jstztzy  阅读(122)  评论(0编辑  收藏  举报