Educational Codeforces Round 114 (Rated for Div. 2) A-D

A

构造含有 n n n组合法括号的 n n n组不同序列

  • 很容易能够想到一种构造方案是先在前面构造 i i i个左括号和右括号,再在后面构造 n − i n-i ni组完整括号, i ∈ [ 1 , n ] i\in [1,n] i[1,n]
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int a[MAXN];
int main(){
    
    
    #ifdef LOCAL
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    ios::sync_with_stdio(false);
    int t, n;
    cin >> t;
    while(t--){
    
    
        cin >> n;
        for(int i=1;i<=n;i++){
    
    
            for(int j=1;j<=i;j++) cout << '(';
            for(int j=1;j<=i;j++) cout << ')';
            for(int j=1;j<=n-i;j++) cout << "()";
            cout << '\n';
        }
    }
    return 0;
}

B

一个字符串由 a , b , c a,b,c a,b,c三种字符构成,分别给出数量,问能不能构造出一个只含有 m m m个相邻字符相同的字符串

  • 考虑构造出相邻字符相同的字符串的最多数量和最少数量,中间的部分显然都能构造出来
  • 最多数量很容易想到,就是把相同的字符都放在一起,因为保证 a , b , c a,b,c a,b,c都大于等于 1 1 1,所以最多是 a + b + c − 3 a+b+c-3 a+b+c3,如果想减少一个,就把一个不同字符放到前面即可
  • 那么最少应该是多少呢?应该容易想到,最好的构造方式就是一个字符一个字符的放,也就是 a b c a b c abcabc abcabc这样,但是开头字符应该是最多的那一个,这样最少应该是最大减第二大减最小减 1 1 1,不细说了
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int a[MAXN];
int main(){
    
    
    #ifdef LOCAL
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    ios::sync_with_stdio(false);
    int t, m;
    cin >> t;
    while(t--){
    
    
        cin >> a[0] >> a[1] >> a[2] >> m;
        sort(a, a + 3);
        int mx = a[0] + a[1] + a[2] - 3;
        int mn = a[2] - a[1] - a[0] - 1;
        if(m >= mn && m <= mx) cout << "YES";
        else cout << "NO";
        cout << '\n';
    }
    return 0;
}

C

给出若干英雄的战斗力,并给出若干龙的攻击力和防御力,现在说只能派出一个英雄去杀龙,当然需要保证英雄的 s t r e n g t h strength strength大于等于龙的防御力。剩下的英雄需要抵御龙的攻击,也就是 s t r e n g t h strength strength和不能低于龙的攻击力,现在说可以给英雄提升 s t r e n g t h strength strength,一个硬币能够提升一点,现在问至少需要使用多少个硬币

  • 看到这个问题应该第一反应不是贪心就是 d p dp dp,又考虑到派一个 s t r e n g t h strength strength大的英雄无论是对于攻击还是防御方面都是不合适的,所以显然是一个贪心,也就是要使用最合适的英雄去杀龙,那么一个明显的思路就是我们选择和龙防御力数值最贴近的英雄去杀他,当然需要考虑他前一个英雄因为有可能那种方案更优
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
ll a[MAXN];
int main(){
    
    
    #ifdef LOCAL
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    ll x, y;
    cin >> n;
    ll sum = 0;
    for(int i=1;i<=n;i++){
    
    
        cin >> a[i];
        sum += a[i];
    }sort(a + 1, a + 1 + n);
    cin >> m;
    for(int i=1;i<=m;i++){
    
    
        cin >> x >> y;
        int p = lower_bound(a + 1, a + 1 + n, x) - a;
        ll ans = 0;
        if(p == n + 1){
    
    
            ans += x - a[n];
            if(y > sum - a[n]){
    
    
                ans += y - sum + a[n];
            }
        }else{
    
    
            if(y > sum - a[p]){
    
    
                ans += y - sum + a[p];
            }
            if(p > 1){
    
    
                ll ans2 = 0;
                p -= 1;
                ans2 += x - a[p];
                if(y > sum - a[p]){
    
    
                    ans2 += y - sum + a[p];
                }
                ans = min(ans, ans2);
            }
        }
        cout << ans << '\n';
    }
    return 0;
}

D

题目意思需要好好理解,给出了若干个装备槽 ( e q u i p m e n t s l o t s ) (equipment slots) (equipmentslots),并给出每个装备槽里面的装备数量,给出每个装备的攻击力,保证按照递增顺序给出,现在给出若干个禁止,每组禁止都是 n n n个,表示禁止这 n n n组装备的某些组合,用下标作为输入。现在想从每一个装备槽里面拿出一件装备,问最大的攻击力之和的可能装备组合是什么,输出任意一组答案

  • 理解题目以后,一个显然的思路是我把所有情况都拿出来,从大到小一个一个看,找到第一个没被禁止的即可,那么怎么实现呢?想了半天总是不知道如何去遍历每一种情况。这里参照tourist大神的写法,使用一个 s e t < p a i r < i n t , v e c t o r < i n t > > > set<pair<int,vector<int>>> set<pair<int,vector<int>>>,其中 f i r s t first first表示和, s e c o n d second second表示选择的是哪些位置,开始的时候,我们把所有装备槽里最大值都放进去,作为集合里的一个元素,然后每次都弹出集合最大的那一组,因为 s e t set set本身就是有序的,默认升序,那么我们从后往前遍历,就是降序,也就是每次弹出集合的末尾元素,怎么做呢?可使用 p r e v prev prev函数,也就是找到 e n d ( ) end() end()的前一个地址,大神代码果然处处都是细节
  • 那么我们可以把这 n n n个装备槽每次都拿出下一件装备,然后放到集合里面,这里显示出使用集合的好处,就是不用判重了,不然每次都要判断这个状态是不是已经出现过,做完 n n n次,当然这里需要判断每个装备槽里面是否只剩下一件装备,如果只剩下一件装备,那这个时候就不能往下看了,也就是跳过这一种情况
  • 那么如何输出答案呢?从 b a n ban ban掉的那些局面中二分查找,现在集合末尾就是可能的答案,如果这种局面没有被 b a n ban ban,那么这就是答案,输出即可
  • 下面基本就是tourist大神的代码,我自己又写了一遍,码风实在是好
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <set>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int a[MAXN];
int main(){
    
    
  #ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
  #endif
  ios::sync_with_stdio(false);
  int n, m;
  cin >> n;
  vector<int> c(n);
  vector<vector<int>> a(n);
  for(int i=0;i<n;i++){
    
    
    cin >> c[i];
    a[i].resize(c[i]);
    for(int j=0;j<c[i];j++){
    
    
      cin >> a[i][j];
    }
  }
  cin >> m;
  vector<vector<int>> f(m, vector<int>(n));
  for(int i=0;i<m;i++){
    
    
    for(int j=0;j<n;j++){
    
    
      cin >> f[i][j];
      f[i][j] -= 1;
    }
  }
  sort(f.begin(), f.end());
  set<pair<int, vector<int>> > s;
  {
    
    
    int sum = 0;
    vector<int> v;
    for(int i=0;i<n;i++){
    
    
      sum += a[i].back();
      v.push_back(c[i] - 1);
    }
    s.emplace(sum, v);
  }
  while(!s.empty()){
    
    
    auto it = prev(s.end());
    int sum = it->first;
    vector<int> v = it->second;
    s.erase(it);
    auto iter = lower_bound(f.begin(), f.end(), v);
    if(iter == f.end() || *iter != v){
    
    
      for(int i=0;i<n;i++){
    
    
        if(i > 0) cout << ' ';
        cout << v[i] + 1;
      }
      cout << '\n';
      break;
    }
    for(int i=n-1;i>=0;i--){
    
    
      if(v[i] > 0){
    
    
        int newsum = sum - a[i][v[i]] + a[i][v[i] - 1];
        v[i] -= 1;
        s.emplace(newsum, v);
        v[i] += 1;
      }
    }
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/roadtohacker/article/details/120403044