Educational Codeforces Round 47 (Rated for Div. 2) 题解(A-E)

A. Game Shopping

思路:简单模拟

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int n, m;
int a[maxn], c[maxn];
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for(int i = 1; i <= m; i++) {
        scanf("%d", &c[i]);
    }
    int ans = 0;
    int p = 1;
    int q = 1;
    while(p <= n && q <= m) {
        if(a[p] <= c[q]) {
            ans++;
            p++;
            q++;
        } else {
            p++;
        }
    }
    printf("%d\n", ans);
    return 0;
}

B. Minimum Ternary String

题意:给出你一串只有0 1 2 的字符串,其中0和1可以进行交换,1和2可以进行就交换,最后让你输出经过上面两种操作若干次后字典序最小的字符串。

思路:经过自己手动的模拟后,你可以发现在第一个2之前的01串的最优结果是将0排在所有1的前面。(因为0和1能够进行交换,导致必然能够出现上述的最优情况),然后从出现第一个2开始的字符串的最优情况是把这之中所有的1放在这个字符串的开头,然后其余的0和2的保持相对顺序不变。
这个结论其实是很显然的,因为0和2不能交换,所以只能保持相对顺序,而1和0 2都可以进行交换。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
typedef long long ll;
string s;
map<int, int>mp;
int a[maxn];
int main() {
    cin >> s;
    int n = s.size();
    for(int i = 0; i < n; i++) {
        a[i + 1] = s[i] - '0';
    }
    int p = -1;
    for(int i = 1; i <= n; i++) {
        if(a[i] == 2) {
            p = i;
            break;
        } else mp[a[i]]++;
    }
    for(int i = 1; i <= mp[0]; i++) printf("0");
    for(int j = 1; j <= mp[1]; j++) printf("1");
    if(p==-1) {
        return 0;
    }
    mp.clear();
    vector<int>v;
    v.push_back(2);
    for(int i = p + 1; i <= n; i++) {
        if(a[i] == 1) mp[1]++;
        else v.push_back(a[i]);
    }
    for(int i = 1; i <= mp[1]; i++) printf("1");
    for(int i = 0; i < v.size(); i++) printf("%d", v[i]);
    return 0;
}

C. Annoying Present

题意:一个长度为n的数组起始都是0,然后接下来有m次操作。每个操作都有一个x和d,对于每一次操作你需要选择一个 i [ 1 , n ] (必须选择且一次操作只能有1个i),然后对于数组中的每一个元素都 a [ j ] , j [ 1 , n ] 进行 a [ j ] = a [ j ] + x + d | i j | 操作,问你经过m次操作之后,数组的平均值最大为多少.

思路:因为在每次操作中x都是相加的,所以只需要直接加起来就行了。然后由于d是优正负的,所以要想使得数组平均值最大,要使正的最多,负的最少。因此很明显,如果d是正的,那么i的位置应该选择两端使正的最多。如果d是负的,那么i应该选在中间使负的最少。

注意:1.存储的时候不要用浮点类型的,不然会有精度问题。
2.当d是负的时候,注意对n的奇偶进行讨论。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
typedef long long ll;
ll n, m;
ll x, d;
int main() {
    scanf("%I64d%I64d", &n, &m);
    ll ans = 0;
    for(int i = 1; i <= m; i++) {
        scanf("%I64d%I64d", &x, &d);
        ans += x * n;
        if(d == 0) continue;
        else if(d > 0) {
            ans += n * (n - 1) / 2*d;
        } else {
            if(n % 2 == 0) {
                ans += n * n / 4*d;
            } else {
                ans += (n + 1) * (n - 1) / 4*d;
            }
        }
    }
    printf("%f\n", (double)ans / n * 1.0);
    return 0;
}

D. Relatively Prime Graph

题意,给出一个n和m,让你构造一个有n个顶点和m条边的连通图。要求在这个图中,顶点u和v的编号gcd(u,v)=1.

思路:暴力计算所有符合条件的边即可,如果满足了就停止计算并输出答案,计算完所有有效边之后数量< m就输出Impossible

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int n, m;
#define pii pair<int,int>
int a[maxn], b[maxn];
int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}
int main() {
    scanf("%d%d", &n, &m);
    if(n > m + 1) {
        printf("Impossible\n");
        return 0;
    }
    int cnt = 0;
    for(int i = 1; i <= n; i++) {
        if(cnt == m) break;
        for(int j = i + 1; j <= n; j++) {
            if(cnt == m) break;
            if(gcd(i, j) == 1) {
                a[++cnt] = i;
                b[cnt] = j;
            }
        }
    }
    if(cnt < m) printf("Impossible\n");
    else {
        printf("Possible\n");
        for(int i = 1; i <= cnt; i++) {
            printf("%d %d\n", a[i], b[i]);
        }

    }
    return 0;
}

E. Intercity Travelling

题意:有n个点,每一个点都有一个疲劳值a[i],且 a [ i ] < a [ i + 1 ] ,一段路程的总的疲劳值是 Σ a [ i ] 。现在每一个点允许有一个休息点,使得到达了这个点之后的疲劳值重新从 a [ 1 ] 开始计算。那么很明显,假设有n个点,就有 2 n 1 种设立休息点的方法(最后一个点不用考虑,因为设不设立没有影响)。最后问你这所用的方法的平均期望值。

思路:题意有点难理解,但其实就是一个推公式的题目。举个例子,假设有4个点,然后疲劳值分别是 a [ 1 ] , a [ 2 ] , a [ 3 ] , a [ 4 ] 。那么平均期望值可以计算得到 p = 20 a [ 1 ] + 8 a [ 2 ] + 3 a [ 3 ] + a [ 4 ] .
然后从后往前看每一个系数 f [ n ] f [ 4 ] = 1 , f [ 3 ] = 2 2 1 1 2 0 = 3 , f [ 2 ] = 3 2 2 2 2 1 = 8 , f [ 1 ] = 4 2 3 3 2 2 = 20
显然可以发现是有规律的。
具体的就不在这里展开了,可以看代码

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
int n, m, a[maxn];
ll f[maxn];
ll quickpow(ll n, ll base) {
    ll res = 1;
    while(n) {
        if(n & 1) {
            res = res * base % mod;
        }
        n >>= 1;
        base = base * base % mod;
    }
    return res;
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for(int i = n; i >= 1; i--) {
        if(i == n) f[n] = 1;
        else {
            ll t = n - i;
            f[i] = ((t + 1) * quickpow(t, 2) % mod) - (t * quickpow(t - 1, 2) % mod);
            f[i] = (f[i] + mod) % mod;
        }
    }
    ll ans = 0;
    for(int i = 1; i <= n; i++) {
        ans = (ans+f[i] * a[i]) % mod;
    }
    printf("%I64d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81055937