Educational Codeforces Round 114 (Rated for Div. 2) 个人题解

中秋节快乐!

A. Regular Bracket Sequences

题意

输出 n n n个不同的长度为 2 n 2n 2n的合法括号序列.

分析

先输出一个"()()()…"序列.

然后依次输出"(())()", “()(())”,…,也就是每次把第 i i i个和第 i + 1 i+1 i+1个交换,其中 i i i从下标2到n-2,这样恰好 n − 1 n-1 n1个,加上最开始的共 n n n个。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
 
signed main()
{
    DDLC_ESCAPE_PLAN_FAILED;
    int t;
    cin >> t;
    while(t--)
    {
        int n;
        cin >> n;
        string s;
        for(int i = 0; i < n; ++i){
            s += '(';
            s += ')';
        }
        cout << s << endl;
        for(int i = 1; i + 1 < s.size(); i += 2){
            s[i] = '(';
            s[i + 1] = ')';
            cout << s << endl;
            s[i] = ')';
            s[i + 1] = '(';
        }
    }
    return 0;
}

B. Combinatorics Homework

题意

你需要判断是否存在一个字符串:

  1. 恰好a个’A’,b个’B’,c个‘C’
  2. 没有其他字符
  3. 恰好m对相邻且相同的字符对(如"AA")

分析

目标是寻找可以满足要求的 m m m取值范围。

将三种字符的数量排序,找到其个数最多的,假设为’A’,记’B’和’C’的数量和为 s s s

m m m最大取值显然是 a + b + c − 3 a+b+c-3 a+b+c3.

m m m的最小值。把 s s s个字符排开,其有 s + 1 s+1 s+1个位置可以插入’A’。若’A’的数量不超过 s + 1 s+1 s+1,那么肯定可以达到最小状态,即不存在相邻且相同的字符对。可能会想到’A’没有填满所有空缺时有可能’B’或者’C’会出现连续的情况,但其实这种情况发生的话’A’肯定就不是个数最多的了。反之,若’A’的数量超过了 s + 1 s+1 s+1,那么至少出现的相同字符对就是 s + 1 − a s+1-a s+1a对。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
 
signed main()
{
    DDLC_ESCAPE_PLAN_FAILED;
    int t;
    cin >> t;
    while(t--)
    {
        int a, b, c, m;
        cin >> a >> b >> c >> m;
        int mx = a + b + c - 3;
        int p[3] = {a, b, c};
        sort(p, p + 3);
        int r2 = p[0] + p[1] + 1, r1 = p[2];
        int mn = max(0LL, r1 - r2);
        if(mx >= m && mn <= m){
            cout << "YES" << endl;
        }
        else cout << "NO" << endl;
    }
    return 0;

C. Slay the Dragon

题意

m m m条龙和 n n n个勇士,每个勇士的力量是 a i a_i ai,每个龙的防御力为 x i x_i xi,攻击力为 y i y_i yi。对每条龙 i i i,你需要派遣一个勇士,要求力量大于等于 x i x_i xi,如果不足 x i x_i xi,需要支付等量的金币补足差值;同时要求剩余的勇士力量总和大于等于 y i y_i yi,不足用金币补足。问击杀每条龙需要支付的金币至少是多少(每条龙之间分别计算,相互独立)

分析

贪心,对勇士力量升序排序。对每条龙,lower_bound(a+1,a+1+n, x[i])查找出一个勇士 s s s,如果要派遣一个大于等于 x i x_i xi的勇士去,那么必定是派 s s s去。

但又有可能这个 s s s超过 x i x_i xi很多而其他的总和不足 y i y_i yi,这个时候 s − 1 s-1 s1也可能是答案。

所以答案要么是派 s s s去,要么是派 s − 1 s-1 s1去。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn];
int x[maxn], y[maxn];
int pre[maxn];
signed main()
{
    DDLC_ESCAPE_PLAN_FAILED;
    int t;
    t = 1;
    a[0] = 0;
    while(t--)
    {
        int n;
        cin >> n;
        fors(i, 1, n) cin >> a[i];
        int m;
        cin >> m;
        fors(i, 1 , m) cin >> x[i] >> y[i];
        sort(a + 1, a + 1 + n);
        pre[0] = 0;
        fors(i, 1, n) pre[i] = pre[i - 1] + a[i];
        fors(i, 1, m){
            int now = lower_bound(a + 1, a + 1 + n, x[i]) - a;
            int ans = 0;
            if(now == n + 1){
                ans += x[i] - a[n];
                ans += (pre[n - 1] >= y[i] ? 0 : y[i] - pre[n - 1]);
                cout << ans << endl;
            }
            else{
                // 要么选now,要么选now-1.
                ans = (pre[n] - a[now] >= y[i] ? 0 : y[i] - (pre[n] - a[now]));
                if(now == 1){
                    cout << ans << endl;
                    continue;
                }
                int res = 0;
                now--;
                res += x[i] - a[now];
                res += (pre[n] - a[now] >= y[i] ? 0 : y[i] - (pre[n] - a[now]));
                ans = min(ans, res);
                cout << ans << endl;
            }
        }
    }
    return 0;
}

D. The Strongest Build

题意

n ( n ≤ 10 ) n(n\leq 10) n(n10)个单调不下降数组,每个数组长 c i c_i ci,第 i i i个数组的第 j j j个元素表示为 a i j a_{ij} aij,保证 ∑ c i ≤ 2 ⋅ 1 0 5 \sum c_i\leq2·10^5 ci2105,你需要从每个数组中选一个元素,但约定有 m ( m ≤ 1 0 5 ) m(m\leq 10^5) m(m105)个选择方案是不允许的。求一个方案使得所有选择的元素和最大,输出方案。

分析

暴力枚举。首先考虑所有数组都选最后一个元素(最大的),如果这个方案不行,那就枚举所有被禁止的方案。例如,假如某个方案{a,b,c}是禁止的,那么就看{a-1,b,c},{a,b-1,c},{a,b,c-1}有没有禁止,没有就更新答案,这样枚举出来的一定是最优解。

贪心思路:

{ a c 1 , a c 2 , . . . } \{a_{c_1},a_{c_2},...\} {ac1,ac2,...}这个在没有限制条件下的方案被限制了的话,可能的最优解就从 { a c 1 − 1 , a c 2 , . . . } , { a c 1 , a c 2 − 1 , . . . } \{a_{c_1-1},a_{c_2},...\},\{a_{c_1},a_{c_2-1},...\} {ac11,ac2,...},{ac1,ac21,...}里面产生。如果这些方案中也有被限制的,那么就再从这些中枚举每个位置分别将其减一再更新答案。这样可以保证每次都是“退而求其次”,但一定是可选择的里面最优的。毕竟 m ≤ 1 0 5 m\leq 10^5 m105,故最多需要枚举 m n mn mn次。加上二分查找,时间复杂度为 O ( m n log ⁡ m ) O(mn\log m) O(mnlogm)

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const int maxn = 2e5 + 10;
int a[12][maxn];
int n;
set<vector<int> > v;
signed main()
{
    DDLC_ESCAPE_PLAN_FAILED;
    cin >> n;
    fors(i, 1, n){
        cin >> a[i][0];
        fors(j, 1, a[i][0]) cin >> a[i][j];
    }
    int m, p;
    cin >> m;
    vector<int> tmp;
    fors(I, 1, m){
        fors(j, 1, n){
            cin >> p;
            tmp.pb(p);
        }
        v.insert(tmp);
        tmp.clear();
    }
    vector<int> ideal; fors(i, 1, n) ideal.pb(a[i][0]);
    // bool flag = 0;
    if(v.find(ideal) == v.end()){
        for(auto x : ideal) cout << x << ' ';
        cout << endl; return 0;
    }
    else{
        int ans = 0;
        vector<int> f;
        for(auto x : v){
            tmp = x;
            int sum = 0;
            for(int i = 0; i < x.size(); ++i){
                sum += a[i + 1][x[i]];
            }
            for(int j = 0; j < x.size(); ++j){
                if(x[j] - 1 == 0) continue;
                sum -= a[j + 1][x[j]];
                sum += a[j + 1][x[j] - 1];
                x[j]--;
                if(v.find(x) == v.end() && sum > ans) ans = sum, f = x;
                x[j]++;
                sum += a[j + 1][x[j]];
                sum -= a[j + 1][x[j] - 1];
            }
        }
        for(auto x : f) cout << x << ' ';
        cout << endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值