Educational Codeforces Round 125 (Rated for Div. 2)

CF系列题解


题目

A. Integer Moves

原题链接

A. Integer Moves

题意

给定一个整数对 ( x , y ) (x, y) (x,y) ,求从 ( 0 , 0 ) (0, 0) (0,0) 转移过来需要几步,每次转移的直线距离必须是整数,即 ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 \sqrt{(x_1−x_2)^2+(y_1−y_2)^2} (x1x2)2+(y1y2)2 整数

输入格式
第一行包含一个整数 t ( 1 ≤ t ≤ 3000 ) t (1≤t≤3000) t(1t3000) ,表示有t组测试数据。
每个测试数据第一行包含两个整数 x , y ( 0 ≤ x , y ≤ 50 ) x, y (0≤x,y≤50) x,y(0x,y50)

输出格式
输出操作次数。

输入样例:
3
8 6
0 0
9 15

输出样例:
1
0
2

题解

思路

分类讨论即可:

  1. ( x , y ) = ( 0 , 0 ) (x, y) = (0, 0) (x,y)=(0,0) ,不需要操作,输出 0 0 0
  2. x 2 + y 2 \sqrt{x^2+y^2} x2+y2 为整数,只需要操作一次即可,输出 1 1 1
  3. 否则我们可以先走到 ( x , 0 ) (x, 0) (x,0),再走到 ( x , y ) (x, y) (x,y),只需要操作两次,输出 2 2 2

关键在于如何判断条件2,实际上也不难。
注意该题会爆 int 。

代码

#include <bits/stdc++.h>
 
#define int long long
 
using namespace std;
 
typedef long long LL;
 
void solve()
{
    int x, y;
    cin >> x >> y;
 
    if (x == 0 && y == 0) {
        cout << "0\n";
    } else {
        int d = sqrt(x * x + y * y); // 条件二的判断
        if (d * d == x * x + y * y) {
            cout << "1\n";
        } else {
            cout << "2\n";
        }
    }
}
 
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int T;
    cin >> T;
 
    while (T -- ) {
        solve();
    }
 
    return 0;
}

B. XY Sequence

原题链接

B. XY Sequence

题意

给定四个数 n , B , x , y n , B, x, y n,B,x,y ,构造一个序列 a 0 , a 1 , a 2 , … , a n a_0,a_1,a_2,…,a_n a0,a1,a2,,an ,其中 a 0 = 0 a_0=0 a0=0 ,对于任意 i ≥ 1 i≥1 i1 满足:

  1. a i ≤ B a_i≤B aiB
  2. a i = a i − 1 + x a_i=a_{i−1}+x ai=ai1+x
  3. a i = a i − 1 − y a_i=a_{i−1}-y ai=ai1y

使得 ∑ i = 0 n a i \sum_{i=0}^na_i i=0nai 的值最大。

输入格式
第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4) t(1t104) ,表示有t组测试数据。
每个测试数据第一行包含四个整数 n , B , x , y ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ; 1 ≤ B , x , y ≤ 1 0 9 ) n, B, x , y (1≤n≤2⋅10^5; 1≤B,x,y≤10^9) n,B,x,y(1n2105;1B,x,y109)
n n n 的总和不会超过 2 ⋅ 1 0 5 2⋅10^5 2105

输出格式
输出最大的 ∑ i = 0 n a i \sum_{i=0}^na_i i=0nai

输入样例:
3
5 100 1 30
7 1000000000 1000000000 1000000000
4 1 7 3

输出样例:
15
4000000000
-10

题解

思路

因为要使得和最大,因此应该每一个元素都尽可能的大,所以当 a i − 1 + x ≤ B a_{i−1}+x≤B ai1+xB a i = a i − 1 + x a_i=a_{i−1}+x ai=ai1+x ,否则 a i = a i − 1 − y a_i=a_{i−1}-y ai=ai1y
当然这一题也会爆 int

代码

#include <bits/stdc++.h>

#define int long long

using namespace std;

typedef long long LL;

void solve()
{
    int n, B, x, y;
    cin >> n >> B >> x >> y;

    int ans = 0;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++ ) {
        if (a[i - 1] + x <= B) {
            a[i] = a[i - 1] + x;
        } else {
            a[i] = a[i - 1] - y;
        }
        ans += a[i];
    }

    cout << ans << "\n";
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;

    while (T -- ) {
        solve();
    }

    return 0;
}

C. Bracket Sequence Deletion

原题链接

C. Bracket Sequence Deletion

题意

给定一个由 ( ( ( ) ) ) 组成的长度为 n n n 的字符串,你可以进行若干次操作——删去最短的 的前缀。
一个前缀被称为 需要满足以下条件:

  1. 前缀是 常规括号序列(即一个左括号对应一个右括号)。
  2. 前缀是至少是长度为 2 2 2回文 的。

例子:(())()()(()(()))常规括号序列)((()(()))( 不是常规括号序列。 ))(()(()回文序列(), )())( 不是回文序列。
注:感觉这个回文有点恶心,读题读了半小时呜呜呜。

输入格式
第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4) t(1t104) ,表示有t组测试数据。
每个测试数据第一行包含一个整数 n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n(1≤n≤2⋅10^5) n(1n2105) ,表示序列长度。
每个测试数据第二行包含一个字符串 s s s
n n n 的总和不会超过 2 ⋅ 1 0 5 2⋅10^5 2105

输出格式
每个测试数据输出两个整数 c c c r r r ,表示操作次数和剩余字符串的长度。

输入样例:
5
2
()
3
())
4
((((
5
)((()
6
)((()(

输出样例:
1 0
1 1
2 0
1 0
1 1

题解

思路

模拟题,关键在于每次删除的是最短的好的前缀。

  1. 假设此时 s[0] == '(' ,无论是和 s[1] == ')' 还是 s[1] == '(' 均可组成一个好的前缀,因此可以直接删除。(原因:题目要求删除 最短 的好的前缀)。
  2. 否则,此时前缀无法满足体中所给的限制1,即前缀一定不可能是常规括号序列,因此只能和后面的部分构成回文。构成回文我们只需要找到后面第一个 s[j] == s[0] 即可,这部分的实现用双指针随便搞搞就行了。倘若我们找不到,意味着此时的前缀我们已经删不掉了,直接终止循环即可。

只需要遍历一遍字符串,时间复杂度为 O ( n ) O(n) O(n)
细节详见代码(比赛写的很丑,将就一下)。

代码

#include <bits/stdc++.h>

#define int long long

using namespace std;

typedef long long LL;

void solve()
{
    int n;
    cin >> n;

    string s;
    cin >> s;

    int ans = 0; // 记录操作次数
    int last = -1; // last用来记录终止循环时我们删到哪里了
    for (int i = 0; i < n; i ++ ) {
        if (s[i] == '(' && i < n - 1) { // 第一种情况
            ans ++ ;
            i ++ ;
            last = i; // 更新last
            continue;
        } else {
            bool flag = false; // 用flag记录我们是否找到s[j] == s[i]
            for (int j = i + 1; j < n; j ++ ) {
                if (s[j] == s[i]) {
                    flag = true;
                    ans ++ ;
                    i = j;
                    last = i;
                    break;
                }
            }
            if (flag) continue;
            else break; // 找不到的话直接break就行了
        }
        break;
    }

    cout << ans << " " << n - last - 1 << "\n";
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;

    while (T -- ) {
        solve();
    }

    return 0;
}

D. For Gamers. By Gamers

原题链接

D. For Gamers. By Gamers.

题意

n n n 种士兵和 C C C 个硬币,每种士兵有三个属性:招募一个所需要的硬币数 c i c_i ci ,生命值 d i d_i di 和攻击力 h i h_i hi 。给出 m m m 个询问,每个询问包含一个攻击力为 D j D_j Dj 生命值为 H j H_j Hj 的魔王,问击败魔王至少需要花多少钱。
有以下限制:

  1. 每次招募只能选择一种士兵。
  2. 士兵在战斗中不能死亡。
  3. 魔王与士兵的战斗是连续的,即双方会在同一时间攻击。(这是一个简化条件)

输入格式
第一行包含两个整数 n , C ( 1 ≤ n ≤ 3 ⋅ 1 0 5 ; 1 ≤ C ≤ 1 0 6 ) n,C (1≤n≤3⋅10^5; 1≤C≤10^6) n,C(1n3105;1C106) ,含义见题面。
接下来 n n n 行每行包含三个整数 c i , d i , h i ( 1 ≤ c i ≤ C ; 1 ≤ d i , h i ≤ 1 0 6 ) c_i,d_i,h_i (1≤c_i≤C; 1≤d_i,h_i≤10^6) ci,di,hi(1ciC;1di,hi106)
下面一行包含一个整数 m ( 1 ≤ m ≤ 3 ⋅ 1 0 5 ) m (1≤m≤3⋅10^5) m(1m3105)
接下来 m m m 行每行包含两个整数 D j , H j ( 1 ≤ D j ≤ 1 0 6 ; 1 ≤ H j ≤ 1 0 12 ) Dj, Hj (1≤D_j≤10^6; 1≤H_j≤10^{12}) Dj,Hj(1Dj106;1Hj1012),表示询问

输出格式
输出 m m m 个整数,表示击败魔王的最小代价,若不能击败,输出 − 1 -1 1

输入样例:
3 10
3 4 6
5 5 5
10 3 4
3
8 3
5 4
10 15

输出样例:
5 3 -1

输入样例:
5 15
14 10 3
9 2 2
10 4 3
7 3 5
4 3 1
6
11 2
1 1
4 7
2 1
1 14
3 3

输出样例:
14 4 14 4 7 7

输入样例:
5 13
13 1 9
6 4 5
12 18 4
9 13 2
5 4 5
2
16 3
6 2

输出样例:
12 5

题解

思路

切记读题要认真

调和级数复杂度(比赛时群里偷的题解,但也没想出来,呜呜呜太菜了)。

由数据范围得显然要预处理。

由于 条件3 的限制,我们可以不用考虑先后手的问题,同时由于 条件2 的限制,招募多个士兵本质上就是攻击力的叠加,对于生命值没有影响,因此当士兵可以击败魔王时应满足 H / d < h / D H / d < h / D H/d<h/D(大写字母表示魔王,小写字母表示士兵),移项得 H × D < h × d H × D < h × d H×D<h×d ,因此可以得把两个属性合并为一个属性。

有点像这个题:AcWing 125. 耍杂技的牛

接下来就是预处理,我们用一个长度为 C + 1 C+1 C+1 的数组 m a x v a l [ C + 1 ] maxval[C+1] maxval[C+1] 记录当花费为 i i i 时可以达到的最高属性值为 m a x v a l [ i ] maxval[i] maxval[i] 。预处理复杂度为 O ( c + c / 2 + c / 3 + . . . + c / c ) = O ( c l o g c ) O(c+c/2+c/3+...+c/c)=O(clogc) O(c+c/2+c/3+...+c/c)=O(clogc) ,调和级数呜呜呜。

预处理好后对于每个询问直接二分即可,注意这里是严格大于,所以要用 upper_bound 。(STL YYDS)

感谢pzr大佬 Orz

代码

#include <bits/stdc++.h>

#define int long long

using namespace std;

typedef long long LL;

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    vector<int> maxval(m + 1);
    for (int i = 0; i < n; i ++ ) {
        int c, d, h;
        cin >> c >> d >> h;
        maxval[c] = max(maxval[c], d * h);
    }

    for (int i = 1; i <= m; i ++ ) {
        for (int j = 2 * i; j <= m; j += i) {
            maxval[j] = max(maxval[j], maxval[i] * (j / i));
        }
    }

    for (int i = 1; i <= m; i ++ ) {
        maxval[i] = max(maxval[i], maxval[i - 1]);
    }

    int q;
    cin >> q;
    
    while (q -- ) {
        int d, h;
        cin >> d >> h;
        int t = upper_bound(maxval.begin(), maxval.end(), d * h) - maxval.begin();
        cout << (t > m ? -1 : t) << " ";
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值