今天是牛客寒假的第六天,睡醒顺便签了四个题就去打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