Contestant. Rank 9289. Rating -54 (+446 -500).
A. Koxia and Whiteboards
题意
给定序列
思路1
注意到题目所给
一句话,暴力+模拟。
时间复杂度:
当然也可以用优先队列优化时间复杂度,不过优化后差不多,所以不放代码了。
对应AC代码
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
while(t-- > 0){
int n = scanner.nextInt(), m = scanner.nextInt();
int[] a = new int[n];
for(int i=0;i<n;i++) a[i] = scanner.nextInt();
for(int i=0;i<m;i++) {
Arrays.sort(a, 0, n);
a[0] = scanner.nextInt();
}
long ans = 0;
for(int i=0;i<n;i++) ans += a[i];
System.out.println(ans);
}
}
}
思路2
先大胆假设:既然对于
假设如此,但需要注意到一点:操作的顺序是不能更改的。
因此,在排序前,我们需要一并存下来 $bi
那么,我们来考虑如何选取这个
因为替换后的
时间复杂度:
对应AC代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
while (t-- > 0) {
int n = scanner.nextInt(), m = scanner.nextInt();
int[] a = new int[n];
int[][] b = new int[m][2];
for (int i = 0; i < n; i++) a[i] = scanner.nextInt();
for (int i = 0; i < m; i++) b[i] = new int[]{i, scanner.nextInt()};
int lastB = b[m - 1][1];
Arrays.sort(a);
Arrays.sort(b, (o1, o2) -> o2[1] - o1[1]);
long ans = 0;
int i = 0, j = 0, lastChange = 0, lastChangedI = 0, approached = 0;
for (; i < n && j < m; i++) {
if (a[i] < b[j][1]) {
approached = Math.max(approached, b[j][0]);
lastChange = b[j][1];
lastChangedI = i;
ans += b[j++][1];
}
else ans += a[i];
}
for (; i < n; i++) ans += a[i];
if(j == 0) ans = ans - a[0] + lastB;
else if(j < m && approached != m - 1) {
ans = ans - (lastChangedI + 1 > n - 1 ? lastChange : Math.min(lastChange, a[lastChangedI + 1])) + lastB;
}
System.out.println(ans);
}
}
}
有时候很简单的签到题不要想太多
B. Koxia and Permutation
题意
给定
思路
既然要让最大值和最小值的和最小,那么我们就需要让最大值出现的次数尽量少,最小值出现的次数尽量多。
因而,结合区间的移动,我们可以先降序地输出
同理,那么我们就可以在降序输出后升序输出
当然,可以证明交替输出和上述思路得到的序列性质是一样的。
时间复杂度:
对应AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n, k;
scanf("%d %d", &n, &k);
int l = 1, r = n, now = k - 1;
for (int i = 1; i <= n; i++) {
printf("%d ", now > 0 ? r-- : l++);
now--;
if (now == 1 - k) now = k - 1;
}
printf("\n");
}
}
思维题还是要多做做,写太慢了。
而且如果用java写的话,需要使用快读,否则会超时。
C. Koxia and Number Theory
题意
给定序列
做法
- 显然不能出现重复数值
- 考虑每个质数
, 遍历序列 , 统计所有 出现的次数,若全都大于2,判定NO
对于第二步的数学证明
- 假设
和 同余于质数 ,那么 和 同余于 。 - 在1的条件下,要使
不被 整除,则必须满足 。 - 因而,我们需要存在至少一个
的值 ,满足 ,这样,我们就可以使用 中国剩余定理 (CRT) 解出 。 - 任取一个
,若它的出现次数 ,那么存在 符合条件1的条件。此时,根据上面的证明,可以得出 。 - 由上述证明,若所有
,那么无法解出 ,判定为NO。
对于上述证明的具体例子
判定YES的一个例子:
对于下面的输入
1
3
5 7 10
取
取
…
对于每一个
判定NO的一个例子:
对于下面的输入
1
11
6 9 12 14 16 17 18 20 25 28 30
取
中国剩余定理 (CRT)
对于
(1) 计算
(2) 设
(3) 上述方程组的通解为:
更加直观的做法
枚举所有元素,若有重复则判NO;
枚举所有
的数 ,若模 后的序列所有数字出现的次数都大于 ,那么判NO。
第二步的可行性
肉眼可见,当
对于右边界
那么,对于
因而,我们只需遍历到
时间复杂度:
对应AC代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
nxt:while(t -- > 0){
int n = scanner.nextInt();
long[] a = new long[n];
for(int i=0;i<n;i++) a[i] = scanner.nextLong();
for(int i=1;i<n;i++) for(int j=i-1;j>=0;j--) if(a[i] == a[j]){
System.out.println("NO");
continue nxt;
}
for(int i=2;i<=n / 2;i++){
int[] m = new int[i];
boolean f = false;
for(int j=0;j<n;j++) m[(int)(a[j] % i)] ++;
for(int j=0;j<i;j++) {
if(m[j] < 2) {
f = true;
break;
}
}
if(!f){
System.out.println("NO");
continue nxt;
}
}
System.out.println("YES");
}
}
}
数论得多看看力,有时候可以多尝试一些数据来找寻规律。
- 本文链接 https://floating-ocean.github.io/blog_old/posts/3334935914/
- 版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!