首页 > 其他 > 详细

Codeforces Round #320 (Div. 2) [Bayan Thanks-Round]

时间:2019-10-14 22:56:36      阅读:88      评论:0      收藏:0      [点我收藏+]

 

A. Raising Bacteria

数二进制位有多少个1就好了。

 

B. Finding Team Member

题意:
有 $2n$ 个人,任意两个人配对有一个价值,如果一人的目前的最优配对那个人的最优配对也是自己,那么两个人可以配对。

思路:
直接模拟,每次至少能让两个人配对成功。所以复杂度 $O(n ^ 2)$,刚开始用优先队列写了一发,发现RE了,以为是优先队列出锅了,最后才发现是数组开小了。

技术分享图片
#include <bits/stdc++.h>
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;

const int N = 840;
priority_queue<pii> que[N];
int who[N];
int best[N][N];
int pos[N];

int main() {
    freopen("in.txt", "r", stdin);
    int n;
    scanf("%d", &n);
    for (int i = 2; i <= 2 * n; i++) {
        for (int j = 1; j < i; j++) {
            int x;
            scanf("%d", &x);
            que[i].push(pii(x, j));
            que[j].push(pii(x, i));
        }
    }
    for (int i = 1; i <= 2 * n; i++) {
        int cnt = 0;
        pos[i] = 1;
        while (!que[i].empty()) {
            best[i][++cnt] = que[i].top().se;
            que[i].pop();
        }
    }
    while (1) {
        bool flag = 1;
        for (int i = 1; i <= 2 * n; i++) {
            if (who[i]) {
                pos[i] = 2 * n + 1;
                continue;
            }
            while (pos[i] <= 2 * n && who[best[i][pos[i]]]) pos[i]++;
            if (pos[i] <= 2 * n) {
                int ne = best[i][pos[i]];
                while (pos[ne] <= 2 * n && who[best[ne][pos[ne]]]) pos[ne]++;
                if (pos[ne] <= 2 * n && best[ne][pos[ne]] == i) {
                    pos[ne] = 2 * n + 1;
                    pos[i] = 2 * n + 1;
                    who[i] = ne;
                    who[ne] = i;
                    //printf("%d %d\n", i, ne);
                }
            }
        }
        //printf("%d\n", pos[2]);
        for (int i = 1; i <= 2 * n; i++)
            if (!who[i]) flag = 0;
        if (flag) break;
    }
    for (int i = 1; i <= 2 * n; i++)
        printf("%d%c", who[i], " \n"[i == 2 * n]);
    return 0;
}
View Code

 

 

C. A Problem about Polyline

题意:
有一条折线,$(0,0)$ – $(x, x)$ – $(2x, 0)$ – $(3x, x)$ – $(4x, 0)$ – $\dots$ - $(2kx, 0)$ – $(2kx + x, x)$ - $\dots$
给出一个点 $(a, b)$,问存不存在最小的 $x$ 使得点 $(a, b)$ 在折线上。

思路:
$a < b$ 显然没有。
若答案存在,分为两种情况,点 $(a, b)$ 在奇数段和偶数段上。
在奇数段满足 $a - (k - 1)x = b$,即 $a - b = (k - 1)x$ $k$ 为奇数。
在偶数段满足 $a - kx = -b$, 即 $a + b = kx$, $k$ 为偶数。
把第一种情况的 $k$ 看成 $k - 1$,两个情况就只有左边不一样了。
分别求一下答案就行了。

技术分享图片
#include <bits/stdc++.h>
using namespace std;

const double eps = 1e-10;
inline int dcmp(double x) {
    if (fabs(x) <= eps) return 0;
    return x < 0 ? -1 : 1;
}

double get(int sum, int b) {
    int z = sum / b;
    while (z && (z & 1 || sum / z < b)) z--;
    if (!z) return -1;
    return 1.0 * sum / z;
}

int main() {
    int a, b;
    scanf("%d%d", &a, &b);
    if (a < b) {
        puts("-1");
        return 0;
    }
    if (a == b) {
        printf("%d", b);
        puts(".0000000000000");
        return 0;
    }
    double ans1 = get(a + b, b);
    double ans2 = get(a - b, b);
    if (fabs(ans1 + 1) == 0 && fabs(ans2 + 1) == 0) puts("-1");
    else if (fabs(ans1 + 1) == 0) printf("%.10f\n", ans2);
    else if (fabs(ans2 + 1) == 0) printf("%.10f\n", ans1);
    else printf("%.10f\n", min(ans1, ans2));
    return 0;
}
View Code

 

 

D. "Or" Game

题意:
有 $n$ 个数,给你 $k$ 次操作,每次操作是任选一个数能给它乘上一个给的数 $x$。问最后所有数或起来最大为多少。

思路:
搞了半天DP,发现是错的。因为当前最优不一定能使后面最优。
发现乘法相当于让这个数二进制位往高处移,那么把这些操作分散给几个数肯定不比直接给一个数来的优。
所以直接枚举哪个数来乘上这个数就OK了。

技术分享图片
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 2e5 + 7;

ll pre[N], last[N];
ll a[N];
int n, k;
ll x;

ll get(ll x, ll y, int cnt) {
    ll ans = x;
    while (cnt--) ans *= y;
    return ans;
}

int main() {
    freopen("in.txt", "r", stdin);
    scanf("%d%d%lld", &n, &k, &x);
    ll m = 1;
    while (k--) m *= x;
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]), pre[i] = pre[i - 1] | a[i];
    for (int i = n; i >= 1; i--)
        last[i] = last[i + 1] | a[i];
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = max(ans, pre[i - 1] | (a[i] * m) | last[i + 1]);
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

 

 

E. Weakness and Poorness

题意:
给一个序列,求一个 $x$ 使得这个序列每个数都减去 $x$ 后的子段和中绝对值最大的那个最小。

思路:
听起来很像数学中的函数,$x$ 做自变量,子段和做因变量,求一个极值,当 $x$ 很小时,最大子段和显然会很大,当 $x$ 很大时,数字变成负的很小,子段和取绝对值之后又会很大。
所以这个就是一个单峰函数。
三分极值点,$O(n)$ 求最大子段和,因为涉及绝对值,就可以所有数乘以-1再做一次,两次得到的值取最大值即可。

技术分享图片
#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 7;

int n, a[N];
double k[N];
double f[N];

double check(double x) {
    for (int i = 1; i <= n; i++)
        k[i] = a[i] - x;
    f[1] = k[1];
    double ans = f[1];
    for (int i = 2; i <= n; i++) {
        f[i] = max(f[i - 1], 0.0) + k[i];
        ans = max(ans, f[i]);
    }
    for (int i = 1; i <= n; i++)
        k[i] *= -1;
    f[1] = k[1];
    ans = max(ans, f[1]);
    for (int i = 2; i <= n; i++) {
        f[i] = max(f[i - 1], 0.0) + k[i];
        ans = max(ans, f[i]);
    }
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    double l = -1e5, r = 1e5;
    for (int cnt = 0; cnt < 200; cnt++) {
        double ll = l + (r - l) / 3.0, rr = r - (r - l) / 3.0;
        if (check(ll) > check(rr)) l = ll;
        else r = rr;
    }
    printf("%.7f\n", check(l));
    return 0;
}
View Code

 

 

F. LCS Again

题意:
给一个串,长度为 $n$, 给出字符集大小,问能构造出多少长度为 $n$,并且LCS为 $n - 1$ 的串。

思路:
题解没看懂。讨论区的做法很妙。
构造过程就相当于在原串中拿一个位置的字符,再重新任意放回原串。
把颜色相同且连续的看成一段,假设长度为 $g$,字符为 $c$。那么从中取一个 $c$ 再变成任意一种字符放回原串,方案数为 $nm$
不过你不能把一个 $c$ 又放回这一段中,不合法的方案是 $g$。
假设有另外一段字符为 $d$ 长度为 $h$ 的子串,把 $c$ 变成 $d$ 再放入这个段显然只有一种放法。而总放法是 $h + 1$,那么不合法的方案是 $h$。
所以总共的不合法方案就是 $n$。所以对每一段的答案为 $nm - n$,如果有 $k$ 段,则答案为 $k(nm - n)$。
还有一种重复的情况,如 $ababa$ 变成 $babab$,可以是第一个字符变成 $b$ 放到最后,也可以是最后一个字符变成 $b$ 放到开头。
这种就是长度大于等于 $2$ 的,用了两种字符的就会重复。用了三种字符的就不会影响。

技术分享图片
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 7;
char s[N];

int main() {
    int n, m;
    scanf("%d%d%s", &n, &m, s);
    long long ans = n * (m - 1);
    for (int i = 1; i < n; i++)
        if (s[i] != s[i - 1])
            ans += n * (m - 1);
    int cur = 1;
    for (int i = 1; i < n; i++) {
        if (cur == 1) {
            if (s[i] == s[i - 1]) continue;
            else cur++;
        } else {
            if (s[i] == s[i - 2]) cur++;
            else {
                ans -= 1LL * cur * (cur - 1) / 2;
                if (s[i] == s[i - 1]) cur = 1;
                else cur = 2;
            }
        }
        printf("%d ", cur);
    }
    ans -= 1LL * cur * (cur - 1) / 2;
    printf("%lld\n", ans);
    return 0;
}
View Code

 

Codeforces Round #320 (Div. 2) [Bayan Thanks-Round]

原文:https://www.cnblogs.com/Mrzdtz220/p/11674372.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!