Codeforces Round #689 (Div. 2, based on Zed Code Competition)

Codeforces Round #689 (Div. 2, based on Zed Code Competition)

A. String Generation

题意: 意思是要你给一个由abc组成的字符串,要求长度为n,其中最长回文子串为k。

题解: 要最长回文子串为k,那么使得最长回文子串为0就好了

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
int const N = 2e5 + 10;
int n, m, T;

int main() {
    cin >> T;
    while(T--) {
        cin >> n >> m;
        string res = "";
        int len = n / 3;
        for (int i = 1; i <= len; ++i) res += "abc";
        int rem = n % 3;
        if (rem == 1) res += "a";
        else if (rem == 2) res += "ab";
        cout << res << endl;
    }
    return 0;
}

B.Find the Spruce

题意: 给一个n*m的网格,每个点为* 或者 . ,问最多构成几个等腰三角形

题解: dp[i][j] = min(dp[i + 1][j - 1], min(dp[i + 1][j], dp[i + 1][j + 1])) + 1

代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;

typedef long long LL;
int t, n, m, res[1000][1000];
char mp[1000][1000];

int main() {
   cin >> t;
   while (t--) {
       cin >> n >> m;
       for (int i = 0; i < n; i++) {
           for (int j = 0; j < m; j++) {
               cin >> mp[i][j];
               res[i][j] = 0;
           }
       }
       LL anss = 0;
       for (int i = n - 1; i >= 0; i--) {
           for (int j = 0; j < m; j++) {
               if (mp[i][j] == '*') {
                   res[i][j]++;
                   if (i != (n - 1) && (j != 0) && (j != m - 1)) {
                       int temp = 0;
                       temp = min(res[i + 1][j],
                                  min(res[i + 1][j - 1], res[i + 1][j + 1]));
                       if (temp) res[i][j] += temp;
                   }
               }
               anss += res[i][j];
           }
       }
       cout << anss << endl;
   }
   return 0;
}

C. Random Events

题意: 给定n个数字,分别为1~n的全排列。给定m个操作,每次操作给定r,p,分别表示有p的概率能够使得a[1 ~ r]有序。问经过m次操作,能够使得整个数组有序的概率是多少?

题解: 考虑将[r, p]结构体按照r从小到大排序,那么必然要倒着往前看,如果当前区间[1 ~ ri]能够成功排序,那么需要乘上p,否则乘上失败的概率(1 - p)继续往前看。

按照上面的处理会很复杂,其实根本不需要,概率题很多时候可以直接考虑1 - 失败的概率。

我们可以维护失败的概率。首先倒着往前看,找到第一个a[i] != i的位置pos。然后如果要失败,只需要满足r >= pos,因为如果r < pos,必然失败,那就乘上概率1,不需要考虑。然后每次如果r >= pos,那么乘上(1 - p)。最后答案为1 - res

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
int const MAXN = 2e5 + 10;
int n, m, T, a[MAXN];

int main() {
    cin >> T;
    while(T--) {
        cin >> n >> m;
        for (int i = 1; i <= n; ++i) scanf("%d", a + i);
        int pos = n;
        while(pos > 0 && a[pos] == pos) pos--;
        double res = 1.0;
        for (int i = 1; i <= m; ++i) {
            int r;
            double p;
            cin >> r >> p;
            if (r >= pos) res *= (1 - p);
        }
        if (pos == 0) res = 0;
        printf("%.10lf\n", 1 - res);
    }
    return 0;
}

D. Divide and Summarize

题意: 给你一个数组,设mid=(数组中最大元素+最小元素)/2,你可以把小于等于mid的数放在一堆,大于mid的数放在一堆形成两个新的数组。同样,新形成的两个数组也可以进行相同操作。给你一堆询问,每次询问给出一个数,问是否有通过这样方式构造的数组的元素和等于这个数。

题解: 只需要将所有的情况得到的值存储起来,然后在之后的问询阶段判断是否有这个值就可以了。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
int const N = 2e5 + 10;
int n, m, T, a[N];
LL sum[N];
set<LL> s;

void dfs(int l, int r) {
    if (l > r) return;
    LL this_sum = 0;
    if (!l) this_sum = sum[r];
    else this_sum = sum[r] - sum[l - 1];
    s.insert(this_sum);
    if (l == r) return;
    int mid = (a[l] + a[r]) / 2;
    int pos = upper_bound(a + l, a + r + 1, mid) - a;
    if (pos == r + 1 || pos == l) {
        return;
    }
    pos--;
    dfs(l, pos);
    if (pos <= r) dfs(pos + 1, r);
}

int main() {
    cin >> T;
    while(T--) {
        int n, q;
        scanf("%d%d", &n, &q);
        for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
        sort(a, a + n);
        for (int i = 0; i < n; ++i) {
            if (!i) sum[i] = a[i];
            else sum[i] = sum[i - 1] + a[i];
        }
        s.clear();
        dfs(0, n - 1);
        for (int i = 1; i <= q; ++i) {
            LL query;
            scanf("%lld", &query);
            if (!s.count(query)) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}

E. Water Level

题意: 初始在饮水机中有k升水,每天需要消耗x升水,每天的一开始,John可以选择往饮水机中加y升水(可以不加)。问t天内是否能保证每时每刻饮水机内的水大于等于l升,小于等于r升。即k ′ ∈ [ l , r ]

题解: 这个大佬的题解讲的很明白了。主要的就是要注意到x的范围,然后分类讨论。https://blog.csdn.net/sigh_/article/details/111064024

以下是引用这个大佬的博客内容:

因为饮水机中的水都是要求在 [ l , r ] 内,可以从 k − = l , r − = l,这样就能忽略 l l l的影响(从k升水中扣除l升水,该部分不可用)。 除了x,所有的数据范围都在1e18,所以可以考虑从x入手,分类讨论:

若 x > y,显然水位每天都会下降。此时考虑水能够多少天使用,常规状态下每天减少 ( x − y ) 升水,注意第一天能否加水,和第一天的水是否够用。

若 x ≤ y , 让饮水机中的水尽量少,如果够一天的使用,则不加水,如果不够一天的使用则加水。设k为饮水机中的剩余水量。当 k<x时,则必须加水:
若 k + y > r,不能加水,无解。
若 k + y ≤ r ,能加水,则 k + = y ,计算当前水能用几天,并且 k % = x,若k在之前中的计算中出现过,则说明这些操作形成了循环,能保证水量一直在 [ 0 , r ] 间,则有解。
若 t ≤ 0 ,退出循环,则有解。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
int const MAXN = 2e5 + 10;
int n, m, T;
unordered_map<LL, int> mp;

// x消耗,y添加,k一开始
int check(LL k, LL r, LL t, LL x, LL y) {
    if (x > y) {
        LL day = 0;
        if (k + y > r) {
            if (k < x) day = 0;
            else day = 1 + (k - x) / (x - y);
        }
        else day = k / (x - y);
        return day >= t;
    }
    else {
        t -= k / x;
        k = k % x;
        mp[k] = 1;
        while(t > 0) {
            if (k + y > r) return 0;
            t -= (k + y) / x;
            k = (k + y) % x;
            if (mp.count(k)) return 1;
            mp[k] = 1;
        }
        return 1;
    }
}

int main() {
    LL k, l, r, t ,x, y;
    cin >> k >> l >> r >> t >> x >> y;
    if (check(k - l, r - l, t, x, y)) puts("Yes");
    else puts("No");   
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值