CodeForces round #867(Div.3)
A题
题意:可以耗费一秒跳到下一个视频,问给t秒时间,能观看的最有价值的视频的值为多少。
思路:简单暴力即可,遍历到当前元素时,默认之前的元素都跳过了,求值即可。
代码:
private static void problemA(Fast fast) {
int t = fast.nextInt();
while(--t >= 0) {
int n = fast.nextInt();
int time = fast.nextInt();
var times = new int[n + 1];
var values = new int[n + 1];
for (int i = 1; i <= n; i++) {
times[i] = fast.nextInt();
}
for (int i = 1; i <= n; i++) {
values[i] = fast.nextInt();
}
int max = -1;
int id = -1;
int skip = 0;
for (int i = 1; i <= n; i++) {
if (times[i] + skip <= time) {
if (max < values[i]) {
max = values[i];
id = i;
}
}
skip++;
}
fast.write(id + "\n");
}
fast.flush();
}
B题
题意:求数组中两个元素乘积的最大值。
思路:因为数组中的元素可能为负,所以可以先将数组中两个最大的元素相乘,再将数组中两个最小的元素相乘,然后再比较大小即可。
代码:
private static void problemB(Fast fast) {
int t = fast.nextInt();
while(--t >= 0) {
int n = fast.nextInt();
var arr = new Long[n];
for (int i = 0; i < n; i++) {
arr[i] = fast.nextLong();
}
Arrays.sort(arr);
long ans = Math.max(arr[0] * arr[1], arr[n - 1] * arr[n - 2]);
fast.write(ans + "\n");
}
fast.flush();
}
C题
题意:求特定矩阵的所有线条和。
思路:观察规律可知,在n * n的矩阵中,
最大边长有4条,n - 1的有一条,数值为1的边长为3条,其余n - 2到2的边长都各有一条,所以求和即可。
代码:
private static void problemC(Fast fast) {
int t = fast.nextInt();
while(--t >= 0) {
int n = fast.nextInt();
long sum = 5L * n;
sum += ((long) (n - 1) * (n - 2));
fast.write(sum + "\n");
}
fast.flush();
}
D题
题意:构造一个1 - n 的全排列数组,要求数组的前缀和对n取模能构造成一个0 到 (n - 1)的全排列数组。
思路:规律题,首先暴力n为1 - 12的情况下,符合题意的全排列数组有哪些,发现除了1以外,n为奇数的情况下无法构造符合题意的数组,偶数能构造出符合题意的数组。再观察样例四给出的数组的特性,发现构造出来的数组,前缀和对n取模的值为0 5 1 4 2 3,所以按照这个规律模拟构造数组即可。
代码:
private static void problemD(Fast fast) {
int t = fast.nextInt();
while(--t >= 0) {
int n = fast.nextInt();
if (n == 1) {
fast.write(1 + "\n");
fast.flush();
continue;
} else if ((n & 1) == 1) {
fast.write(-1 + "\n");
fast.flush();
continue;
}
var list = new ArrayList<Integer>();
int start = 0, end = n - 1;
for (int i = 1; i <= n >> 1; i++) {
list.add(start++);
list.add(end--);
}
fast.write(n + " ");
for (int i = 1; i < n; i++) {
int pre = list.get(i - 1);
int cur = list.get(i);
if (cur > pre) {
fast.write(cur - pre + " ");
} else {
fast.write(n + cur - pre + " ");
}
}
fast.write("\n");
fast.flush();
}
}
E题
题意:要求字符串s[i]≠s[n−i+1],询问给定的字符串最少交换多少次字符才能符合要求。
思路:我们首先判断哪些字符串不可能符合s[i]≠s[n−i+1]这一要求,长度为奇数或者某一字符数量大于字符串长度的一半。
其余的情况下,我们应该优先把满足s[i] == s[n - i + 1]的一对字符和另外一对字符做一次交换,(这两对字符不相同)。如果有一种字符对的数量大于其余所有字符对的数量,那这个字符对剩余的数量就必须和本来就满足s[i]≠s[n−i+1]的其他字符做交换了。
代码:
private static void problemE(Fast fast) {
int t = fast.nextInt();
go: while(--t >= 0) {
int n = fast.nextInt();
String s = fast.nextLine();
if ((n & 1) == 1) {
fast.write("-1\n");
continue;
}
char[] chars = new char[n + 1];
var cMap = new HashMap<Character, Integer>();
for (int i = 1; i <= n; i++) {
chars[i] = s.charAt(i - 1);
cMap.merge(chars[i], 1, Integer::sum);
}
for (var num : cMap.values()) {
if (num > n >> 1) {
fast.write("-1\n");
continue go;
}
}
var map = new HashMap<Character, Integer>();
int sum = 0;
for (int i = 1; i <= n >> 1; i++) {
if (chars[i] == chars[n - i + 1]) {
map.merge(chars[i], 1, Integer::sum);
sum++;
}
}
int cnt = 0;
for (var value : map.values()) {
if (value << 1 > sum) {
cnt = (value << 1) - sum;
break;
}
}
cnt += (sum - cnt + 1) >> 1;
fast.write(cnt + "\n");
}
fast.flush();
}
F题
题意:本质上就是求出根节点到叶子节点的距离以及叶子节点到其他叶子节点的距离。
思路:我们将每个节点都视为一个子树,那么这个子树目前所付出的代价是c * deep,他到叶子节点的距离前二大的值分别为len1和len2,那么他所能得到的最大值即为len1 * k + (k - c) * len2 - c * deep;每个子树到所有叶子节点的距离可用dfs求解,然后排序挑出前二大的值即可。
代码:
static long maxCnt = 0;
private static void problemF(Fast fast) {
int t = fast.nextInt();
while(--t >= 0) {
maxCnt = 0;
var map = new HashMap<Integer, List<Integer>>();
int n = fast.nextInt();
int k = fast.nextInt();
int c = fast.nextInt();
for (int i = 1; i < n; i++) {
int u = fast.nextInt();
int v = fast.nextInt();
map.computeIfAbsent(u, value -> new ArrayList<>()).add(v);
map.computeIfAbsent(v, value -> new ArrayList<>()).add(u);
}
var list = new ArrayList<Integer>();
for (var v : map.get(1)) {
var len = dfsLen(v, 1, 1, map, c, k);
list.add(len);
}
list.sort((a, b) -> b - a);
var ans = (long) list.get(0) * k;
if (c < k && list.size() > 1) {
ans += (long) list.get(1) * (k - c);
}
maxCnt = Math.max(maxCnt, ans);
fast.write(maxCnt + "\n");
}
fast.flush();
}
private static int dfsLen(Integer u, int step, int fa, Map<Integer, List<Integer>> map, int c, int k) {
int max = step;
var list = new ArrayList<Integer>();
for (var v : map.get(u)) {
if (v != fa) {
var len = dfsLen(v, step + 1, u, map, c, k);
list.add(len - step);
max = Math.max(max, len);
}
}
list.sort((a, b) -> b - a);
if (list.size() > 1) {
long pre = (long)step * c;
long ans = (long) list.get(0) * k + (long) list.get(1) * (k - c) - pre;
maxCnt = Math.max(maxCnt, ans);
}
return max;
}
G题
题意:求数组中满足a[i],a[j],a[k]为等比数列的数量有多少个。
思路:我们可以遍历每一个中间元素,即将原数组中每一个元素视为a[j];我们找a[j]的所有因子,(用sqrt(n)的方式)然后得出a[i]和a[k]即可。G1难度的数据范围是1e6,G2难度的题目a[i]的数据范围为1e9,观察数据范围可以想到,当a[i]大于等于1e6时,因为a[k]必须小于等于1e9,所以a[i]的因子必须小于等于1e3,此时暴力枚举1e3即可。需要注意的是,此题卡了long类型的时长,a[i]必须存为int类型。
代码:
private static void problemG2(Fast fast) {
int t = fast.nextInt();
while(--t >= 0) {
int n = fast.nextInt();
var map = new HashMap<Integer, Long>(n);
for (int i = 0; i < n; i++) {
map.merge(fast.nextInt(), 1L, Long::sum);
}
long sum = 0;
for (var value : map.values()) {
if (value >= 3) {
sum += value * (value - 1) * (value - 2);
}
}
for (var i : map.keySet()) {
if (i <= (int) 1e6) {
for (int k = 2; k * k <= i; k++) {
if (i % k == 0) {
sum += map.getOrDefault(i / k, 0L) * map.getOrDefault(i, 0L) * map.getOrDefault(i * k, 0L);
if (i != k * k) {
long cnt = (long) i * i / k;
if (cnt <= Integer.MAX_VALUE) {
sum += map.getOrDefault(k, 0L) * map.getOrDefault(i, 0L) * map.getOrDefault((int) cnt, 0L);
}
}
}
}
if (i != 1) {
long cnt = (long) i * i;
if (cnt <= Integer.MAX_VALUE) {
sum += map.getOrDefault(1, 0L) * map.getOrDefault(i, 0L) * map.getOrDefault((int)cnt, 0L);
}
}
} else {
for (int k = 2; k <= 1000; k++) {
if (i % k == 0) {
long cnt = (long) i * k;
if (cnt <= Integer.MAX_VALUE) {
sum += map.getOrDefault(i / k, 0L) * map.getOrDefault(i, 0L) * map.getOrDefault((int)cnt, 0L);
}
}
}
}
}
fast.write(sum + "\n");
}
fast.flush();
}

本文介绍了CodeForces比赛第867轮Div.3中的A至G题,涉及动态规划、数组操作、查找因子、等比数列计数和线性搜索等问题,展示了相应的算法思路和Java代码实现。
1698

被折叠的 条评论
为什么被折叠?



