Educational Codeforces Round 143 (Rated for Div. 2)(vp)

        A. Two Towers

思路:将第二个串从右往左接到第一个串上,然后遍历第一个串,并记录存在连续两个相同颜色block的个数与是否存在连续3个相同颜色的block,如果连续2个相同个数大于一或者存在连续三个相同block,输出NO。

#include <iostream>
#include <vector>
#include <string>
using namespace std;


int main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n, m;
        string a, b;
        cin >> n >> m >> a >> b;
        int tag = 0, len = 1, cnt = 0;
        a = a + string(b.rbegin(), b.rend());
        for (int i = 1; i < a.size(); ++i){
            if (a[i] == a[i - 1]) len += 1;
            else len = 1;
            if (len == 2){cnt += 1;}
            if (cnt > 1 || len == 3) {tag = 1; break;}
        }
        cout << (tag == 0 ? "YES" : "NO") << endl;
    }
    return 0;
}

B. Ideal Point

思路:对所有给出的区间扫描,如果K在区间内,则用map将区间内所有出现的point频率加一,如果k不在该区间内,则直接跳过。最后遍历一遍mapp,如果存在出现频率大于等于k出现频率的数,则输出NO,否则输出YES。需要注意的是当mapp为空时,则直接输出NO,因为区间数不为空,所以一定有point频率大于k。

#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;


int main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n, k;
        cin >> n >> k;
        vector<vector<int>> a(n, vector<int> (2));
        map<int, int> mapp;
        for (int i = 0; i < n; ++i){
            cin >> a[i][0] >> a[i][1];
            if (a[i][0] <= k && k <= a[i][1]){
                int R = a[i][1], L = a[i][0];
                while (L <= R){mapp[L] += 1; L += 1;}
            }
        }
        int tag = 0;
        for(auto x : mapp){
            if ((x.second >= mapp[k] && x.first != k)) { tag = 1; break;}
        }
        if (mapp[k] == 0) tag = 1;
        cout << (tag == 0 ? "YES\n" : "NO\n");
    }
    return 0;
}

C. Tea Tasting

思路:本次VP最经典的开拓思路题。

对于每杯茶被喝完与否,需要找出第几个人刚好喝不完它,那么这个人后面那个就可以喝完这杯茶,于是在扫描输入时保存b的前缀数组。然后遍历数组a,对于每个ai找出一个k值,从i~k每个人都喝了bj,然后再判断茶是否有剩,如果有剩且k<n,则把多余的茶加到b[k+1]身上。

到目前为止的关键点是找到第k个人,可以用二分,也可以用low_bound函数。这里采用倍增查找。

查找到k以后,需要保存区间,对于区间[i, k]中每个人都喝了bj(i <=j <= k),需要保存信息,在最后输出时直接用该信息*bj+该位置多余的茶即可。这里采用差分数组,如果i~k每个人都喝了一次,那么d[i] += 1, d[k + 1] -= 1(如果k < n的话)

#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;


int main(){
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n;
        cin >> n;
        vector<long long int> a(n + 1), b(n + 1), r(n + 1, 0), s(n + 1, 0), d(n + 1, 0);
        for (int i = 1; i <= n; ++i){
            cin >> a[i];
        }
        for (int i = 1; i <= n; ++i){
            cin >> b[i];
            s[i] += s[i - 1] + b[i];
        }
        for (int i = 1; i <= n; ++i){
            int k = i - 1, p = 1, sum = 0;
            while(p){
                if (k + p > n) {p /= 2; continue;}
                if (sum + s[k + p] - s[k] <= a[i]){
                    sum += s[k + p] - s[k];
                    k += p;
                    p *= 2;
                }
                else{
                    p /= 2;
                }
            }
            d[i] += 1;
            if (k < n) d[k + 1] -= 1;
            if (a[i] - sum > 0 && k < n) r[k + 1] += min(a[i] - sum, b[k + 1]);
        }
        for (int i = 1; i <= n; ++i){
            d[i] += d[i - 1];
            cout << r[i] + d[i] * b[i] << " \n"[i == n];
        }
    }
    return 0;
}

总结:这个题目的关键点在于找到前缀和的位置以后,如何保存区间的信息,因为可能对于每杯茶来说,都需要保存一个区间的信息,如果每次保存都从左端点到右端点扫描一遍会运行超时,于是想到了差分数组。对于保存方法而言,还可以应用树状数组将区间内的值加1。(树状数组,待完成23.2.22)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值