复健训练-CF1706(Codeforces Round #809 (Div. 2))

题目在这

 

A. Another String Minimization Problem

题意:给一个长为 m 的全是 'B' 的字符串,给 n 个操作,每个操作有个 $a_i$ ,表示可以把字符串中第 $a_i$ 位或者 $m-a_i+1$ 位变成 'A'。问字典序最小的字符串。

做法:能变得就变,先变前面再变后面。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long

using namespace std;

const int N = 105;
int n, m, a[N], b[N];

void Main(){
    scanf("%d%d", &n, &m);
    rep (i,1,n) scanf("%d", &a[i]);
    rep (i,1,m) b[i] = 1;
    rep (i,1,n){
        if (b[min(a[i], m-a[i]+1)] == 0) b[max(a[i], m-a[i]+1)] = 0;
        else b[min(a[i], m-a[i]+1)] = 0;
    }
    rep (i,1,m) cout<<(char)(b[i] + 'A');
    puts("");
    return;
}

int main(){
    int T; scanf("%d", &T);
    while (T--) Main();
    return 0;
}
View Code

 

B. Making Towers

题意:有 n 个方块,每个方块有一个颜色。现在第一个方块在 (0, 0) ,每个方块放在前一个方块的左边、右边或者上面。如果有一列竖着全都是同一种颜色,那么说构成了这种颜色的 tower 。现在问对于每一种颜色,问最多能搭出该颜色多高的 tower 。

做法:可以发现在一个序列中,如果两个相同颜色中间差了偶数个别的方块,他们就可以搭在一起。差偶数个方块相当于是下标奇偶性不同。所以用一个 $f[0/1][i]$ 表示颜色 i 能搭出多高的塔,$0/1$ 是其所在下标奇偶性,转移就是 $f[t][i] = f[t \oplus 1][i] + 1$ 。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long

using namespace std;

const int N = 1e5+10;
int n, a[N], f[2][N], ans[N];

void Main(){
    scanf("%d", &n);
    rep (i,1,n) ans[i] = f[0][i] = f[1][i] = 0;
    rep (i,1,n){
        scanf("%d", &a[i]);
        f[i&1][a[i]] = f[(i&1)^1][a[i]] + 1;
        ans[a[i]] = max(ans[a[i]], f[i&1][a[i]]);
    }
    rep (i,1,n) printf("%d ", ans[i]); puts("");
    return;
}

int main(){
    int T; scanf("%d", &T);
    while (T--) Main();
    return 0;
}
View Code

 

C. Qpwoeirut And The City

题意:每个 building 有 $h_i$ 层楼,定义一个 building 是 cool 的当且仅当它满足 $h_i>h_{i-1}$ 且 $h_i > h_{i+1}$ (两边的都不是 cool building)。现在可以增加层数(不能减少),问达到最多 cool 的 building 数,最少总共需要加多少层。

做法:n 为奇数,肯定是偶数位的都是 cool ,直接算。 n 为偶数,最多的 cool 数量应该是 $n/2-1$,要达到这个数目,如果当前是 cool ,那么前一个肯定不是 cool ;如果当前非 cool ,那么要么前一个是 cool,要么前前个是 cool ,而且前前个是 cool 的情况最多出现一次。然后我用了一个 dp , $f[i][0/1][0/1]$ 表示到第 i 个 building ,当前是否是 cool ,有没有出现过前前个是 cool 的情况。转移见代码。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long

using namespace std;

const int N = 1e5+10;
const ll inf = 1e18;
int n, a[N];
ll ans, f[N][2][2];

void Main(){
    scanf("%d", &n);
    rep (i,1,n) scanf("%d", &a[i]);
    if (n&1){
        ans = 0;
        for (int i=2; i<n; i+=2)
            ans += max(max(a[i-1], a[i+1]) + 1 - a[i], 0);
        printf("%lld\n", ans);
    } else{
        rep (i,1,n) f[i][0][0] = f[i][1][0] = f[i][0][1] = f[i][1][1] = inf;
        f[1][0][0] = 0;
        rep (i,2,n){
            if (i < n){
                f[i][1][0] = f[i-1][0][0] + max(max(a[i-1], a[i+1]) + 1 - a[i], 0);
                f[i][1][1] = f[i-1][0][1] + max(max(a[i-1], a[i+1]) + 1 - a[i], 0);
            }
            f[i][0][0] = f[i-1][1][0];
            f[i][0][1] = f[i-1][1][1];
            if (i>2) f[i][0][1] = min(f[i-2][1][0], f[i][0][1]);
            if (i==2) f[i][0][1] = min(f[i][0][1], f[i-1][0][0]);
        }
        printf("%lld\n", min(f[n][0][0], f[n][0][1]));
    }
    return;
}

int main(){
    int T; scanf("%d", &T);
    while (T--) Main();
    return 0;
}
View Code

 

D1. Chopping Carrots (Easy Version)

题意:给定 n, k 以及 ${a_i}$ ,要求构造一个 $p_i \in {1,k}$ ,使得 $cost = \max{\lfloor \frac{a_i}{p_i} \rfloor} - \min{\lfloor \frac{a_i}{p_i} \rfloor}$ 最小,输出最小的 cost 。 $n,k,a_i \le 3000$

做法:从 0 到 a[1] 枚举 $\min{\lfloor \frac{a_i}{p_i} \rfloor}$ ,那么只需最小化 max 即可。对于每个 a[i] ,有了 min 这个 max 的最小值其实可以算出来就是 $a[i]/ (a[i]/i)$ ,当然 i = 0 要特判。所以直接对这些取 max 值取 max ,计算答案即可。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)

using namespace std;

const int N = 3005;
int n, m, a[N];

void Main(){
    scanf("%d%d", &n, &m);
    rep (i,1,n) scanf("%d", &a[i]);
    int ans = 3000;
    rep (i,0,a[1]){
        int mx = 0, p;
        rep (j,1,n) p = min(m, i ? (a[j]/i) : (a[j]+1)), mx = max(mx, a[j]/p);
        ans = min(mx - i, ans);
    }
    printf("%d\n", ans);
    return;
}

int main(){
    int T; scanf("%d", &T);
    while (T--) Main();
    return 0;
}
View Code

 

D2. Chopping Carrots (Hard Version)

题意:和上一题一样,$n,k,a_i \le 1e5$ 

做法:不能每个数都算它的 max 值了。考虑对于每个 $a_i$ , $\lfloor \frac{a_i}{p_i} \rfloor$ 的不同值最多只有 $\sqrt{a_i}$ 个,然后我们依然是枚举 $v = \min{\lfloor \frac{a_i}{p_i} \rfloor}$ ,那么相应的 max 值其实是那根号个值里面最小的 $\ge v$ 的值。例如对于某一个 $a_i$ ,其中两个值为 $s_1, s_2 (s_1<s_2)$ ,那么对于 min 值在 $[s_1 + 1, s_2]$ 内它的 max 值都是 $s_2$ 。所以我们保存一个数组 $p[i]$ 表示当 min 值为 i 的时候 max 值应该是多少,相当于对于每个数要一个区间 max ,但这个可以在 $s_1$ 处打标记最后再求前缀 max。求完前缀 max 以后 $p[i]$ 就是对 i 这个最小值的最小的 max 值,求答案即可。

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)

using namespace std;

const int N = 1e5+10;
int n, m, a[N], p[N];

void Main(){
    scanf("%d%d", &n, &m);
    int Mx = 0;
    rep (i,1,n){
        scanf("%d", &a[i]);
        Mx = max(Mx, a[i]);
        int last = 1e9;
        for (int j = 1; j <= min(a[i], m); j = (a[i]/(a[i]/j)) + 1){ //遍历出现不同的 ai/pi 的 pi
            int v = a[i]/j;
            p[v + 1] = max(p[v + 1], last);
            last = v;
        }
        p[0] = max(p[0], last);
    }
    // printf("%d\n", p[0]);
    int ans = 1e9, mx = 0;
    rep (i,0,a[1]){
        mx = max(mx, p[i]);
        ans = min(ans, mx - i);
    }
    printf("%d\n", ans);
    rep (i, 0, Mx+1) p[i] = 0;
    return;
}

int main(){
    int T; scanf("%d", &T);
    while (T--) Main();
    return 0;
}
View Code

 

E 咕咕咕

 

posted @ 2022-07-19 13:21  bestfy  阅读(49)  评论(0编辑  收藏  举报