2020牛客寒假算法基础集训营6-签到之旅

今天是牛客寒假的第六天,睡醒顺便签了四个题就去打APEX了

先写下部分题解吧

A

现在有正整数集 A 和 B,每个集合里有 N 个数,你要建立他们间的一一映射将每对配对的数字相加可以得到 N 个和,你要做的就是最大化第 K 大的和

1≤K≤N≤100,000 输入的所有数字不超过 108
思路:如果要第K大最大,那么我们一定要选取A中最大的K个元素跟B中最大的K个元素,前K个元素的配方一定从这些元素中选取
那么能使这些数配合完,最小值最大的一组,一定是A从小到大,B从大到小配,选取其中的最小值即可。
代码
#include<bits/stdc++.h>
#define LL long long
#define maxn 100010
#define inf 0x3f3f3f3f
using namespace std;
 
LL a[maxn], b[maxn];
 
int main(){
    int n, k;
    cin >> n >> k;
    for(int i = 0; i < n; ++i){
        cin >> a[i];
    }
    for(int i = 0; i < n; ++i){
        cin >> b[i];
    }
    sort(a, a + n);
    sort(b, b + n);
    LL ans = inf;
    for(int i = 0; i < k; ++i){
        ans = min(ans, b[n - i - 1] + a[n - k + i]);
    }
    cout << ans << endl;
    return 0;
}

F

小 Q 新学会了一种魔法,可以对一个 N行M列 的网格上的敌人造成伤害

第 i 次使用魔法可以对网格上的一个十字形区域(即第 xi 行和第 yi 列的并)中的每个格子上的敌人造成 zi 点伤害
现在小 Q 一共使用了 H 次魔法,你需要在所有的施法完成之后统计造成伤害的情况,详见输出描述
提醒:本题输入规模较大,请使用高效的输入方式
1≤H≤500,000 1≤xi,yi,zi,N,M≤2000 1≤xi≤N,1≤yi≤M
 
思路:我们按行和列储存这一行或这一列受到的总伤害,但是这个时候,中心的那个点会被算两遍,可以在最开始的时候先减去这个值,最后一起统计即可
代码
#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define maxn 2010
using namespace std;

LL r[maxn], c[maxn];

int main(){
    int n, m, h;
    scanf("%d %d %d", &n, &m, &h);
    int x, y, z;
    LL ans = 0;
    for(int i = 0; i < h; ++i){
        scanf("%d %d %d", &x, &y, &z);
        ans = (ans - z * (x + y) + mod) % mod;
        r[x] = r[x] + z;
        c[y] = c[y] + z;
    }
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            ans = (ans + (r[i] + c[j]) * (i + j)) % mod;
        }
    }
    printf("%lld\n", ans);
    return 0;
}

G

合法括号序列的定义是:
1.空序列是合法括号序列
2.如果 S 是一个合法括号序列,那么(S)是合法括号序列
3.如果 A 和 B 都是合法括号序列,那么 AB 是一个合法括号序列
现在给定一个括号序列,求最少删去几个括号能得到一个合法的括号序列
输入包含 T 组数据,每组数据中,设括号序列的长度为 N
1≤T,ΣN≤1,000,000
(由于空串是合法的括号序列,所以答案可以是N)
 
思路:设置两个量,f跟b,在遍历S时,f遇到正括号+1,否则-1,如果f小于0则把f置0,并把b+1
很明显,b就表示了需要去掉多少个反括号,f表示需要去掉多少个正括号,相加即为答案
代码
#include<bits/stdc++.h>
using namespace std;

int main(){
    int T;
    cin >> T;
    while(T--){
        int n;
        string s;
        cin >> n >> s;
        int f = 0, b = 0;
        for(int i = 0; i < n; ++i){
            if(s[i] == '('){
                f++;
            }
            else{
                f--;
            }
            if(f < 0){
                b++;
                f = 0;
            }
        }
        cout << abs(f) + b << endl;
    }
}

J

现有一个边长为正整数的三角形,问能否以其三个顶点为圆心画三个圆,使三个圆两两外切
三边长均不超过108
 
思路:分为两种情况,一是三边能组成三角形,二是不能(直接输出指定字符串)
对于一,我们设边长为A,B,C,三个圆半径为a,b,c,有a+b = A, b+c = B, c+a = C
那么很显然,我们只需要先把A,B,C降序排列,再依次输出((A+B-C)/2, (A+C-B)/2, (C+B-A)/2)(升序输出)
代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;

int main(){
    double a, b, c;
    cin >> a >> b >> c;
    if(max(max(a, b), c) >= (a + b + c - max(max(a, b), c))){
        cout << "wtnl" << endl;
        return 0;
    }
    cout << "Yes" << endl;
    if(a > b){
        swap(a, b);
    }
    if(a > c){
        swap(a, c);
    }
    if(b > c){
        swap(b, c);
    }
    printf("%.2lf %.2lf %.2lf\n", (a + b - c) * 0.5, (a + c - b) * 0.5, (c + b - a) * 0.5);
    return 0;
}

签完就去APEX了,然而打了一下午也没吃到鸡QAQ

 

猜你喜欢

转载自www.cnblogs.com/Hebut-Amadeus/p/12313448.html