Codeforces Round #619 (Div. 2)

题目链接:https://codeforces.com/contest/1301

A - Three Strings

水题

B - Motarack's Birthday

题意:给一个数组,至少一个位置是空的,要求给所有的空的位置填上同一个数字x,使得相邻两个数字的差最小,有多种x输出任意一种。

题解:显然相邻两个数字的差,要么是固定的两个数字提供的,要么就是一个数字和一个空位提供的(两个空位之间是没有差的)。只需要找到空位两边的最大值和最小值,这个时候x肯定是选择这俩的平均值(假如有两个平均值,选择任意一个)。

C - Ayoub's function

题意:在n个数字0中,选恰好m个变成1。使得这个数字字符串中,包含至少一个1的子串最多。输出最多有多少个包含至少一个1的子串。

题解:子串个数是恒定的,所以等价于要全是0的子串最少。打表发现貌似是平均分配0的情况下满足题意。写了一个这个东西。

应该准确一点的证明是这样:考虑两个全为0的子串,总长为l,其中一个长为x,那么他们贡献的全为0的子串的个数就是: \(f(x)=\frac{1}{2}x(x+1)+\frac{1}{2}(l-x)(l-x+1)\)\(f(x)=\frac{1}{2}(2x^2-2lx+l^2+l)\) 意思就是尽可能平均的时候取到最小值。

void test_case() {
    ll n, k;
    scanf("%lld%lld", &n, &k);
    if(k == 0) {
        puts("0");
        return;
    }
    ll ans = (n + 1) * n / 2;
    if(n == k) {
        printf("%lld\n", ans);
        return;
    }
    ll cn = n - k;
    if(cn <= k) {
        printf("%lld\n", ans - cn);
        return;
    }
    ++k;
    ll m1 = cn / k;
    ll m2 = m1 + 1;
    ll c2 = cn % k;
    ll c1 = (cn - (c2 * m2)) / m1;
//    printf("m1=%lld m2=%lld\n", m1, m2);
//    printf("c1=%lld c2=%lld\n", c1, c2);
//    printf("cn=%lld sum=%lld\n", cn, c1 * m1 + c2 * m2);
    ans -= ((m1 + 1) * m1) / 2 * c1;
    ans -= ((m2 + 1) * m2) / 2 * c2;
    printf("%lld\n", ans);
}

总结:注意有k个1,是把0分成k+1份,注意特判不够分的情况,这时平均值的下整是0,有可能会RE:dividing by zero。

*D - Time to Run

题意:给一个 \(n*m(1\leq n \leq 500,1\leq m\leq 500)\) 个格子,相邻格子x,y之间有两条边,分别是x->y和y->x。限制:每条边至多经过1次,且起始格子必须在左上角,求是否能恰好走k条边。

题解:不妨设 \(m>=n\) 一开始想到一种策略,就是逐行扫描,每次走到最右然后折返到最左,再向下移动,这样至多移动 \(n*(m-1)*2+(n-1)\) 次,写出了一种(蠢的,浪费步骤的)实现,交上去WA了。想到左右向的边已经充分利用了,但是只用了向下的一条完整的边。考虑上面的构造肯定是不优的,因为我到了左下角之后至少还能向上走回去。再想想可以在回来的时候逐列扫描,也就是每次先向上走,再向下走,到底边之后再向左移动。发现这样的构造是可以遍历所有的边的,所以答案就是这种遍历所有边的构造。

写的时候注意,限制只能有3000行输出,平均给每行每列就只有3行输出,一开始还搞什么/4又%4的,白白浪费步骤,上面这个构造中每行每列至多使用了3行输出进行扫描。去掉/4又%4之后还要注意,每次移动不能是0格。

pair<int, char> ans[3005];
int atop;

void add(int &k, int x, char c) {
    if(x) {
        ans[++atop] = {x, c};
        k -= x;
    }
}

void test_case() {
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    if(k > 4 * n * m - 2 * n - 2 * m) {
        puts("NO");
        return;
    }

    atop = 0;
    int y = 1;
    while(k) {
        add(k, min(m - 1, k), 'R');
        if(y == n)
            break;
        add(k, min(m - 1, k), 'L');
        add(k, min(1, k), 'D');
        ++y;
    }
    int x = m;
    while(k) {
        add(k, min(n - 1, k), 'U');
        add(k, min(n - 1, k), 'D');
        add(k, min(1, k), 'L');
        --x;
    }

    puts("YES");
    printf("%d\n", atop);
    for(int i = 1; i <= atop; ++i)
        printf("%d %c\n", ans[i].first, ans[i].second);
}
posted @ 2020-02-14 02:15  KisekiPurin2019  阅读(257)  评论(0编辑  收藏  举报