Codeforces Round 859 (Div. 4)原题地址https://codeforc.es/contest/1807
A:Plus or Minus
https://codeforc.es/contest/1807/problem/A
题意:题目意思就是如果输入的第1,2个数可以相加等于第3个数就输出‘+’,否则输出‘-’。共有t次测试。
附上关键部分的代码:
int T = in.nextInt();
while(T-->0)
{
int n = in.nextInt();
int m = in.nextInt();
int k = in.nextInt();
if(n + m == k)
{
out.println("+");
continue;
}
else
{
out.println("-");
continue;
}
}
B: Grab the Candies
https://codeforc.es/contest/1807/problem/B
题意:有两个人,一有若干袋糖果,一人拿奇数个糖果的袋子,每个人依次拿一袋糖果,询问是否可以通过重新排列糖果的顺序使得拿偶数糖果的人最终拿的糖果数目比拿每次拿奇数2个数的人拿的多,可以输出“YES”,不可以输出'NO".
题解:我们可以发现,不论怎么重排拿糖果的顺序,始终两个人拿糖果的数量总是所有奇数糖果数之和与所有偶数糖果数之和,那么我们只需要看每一堆糖果数目的奇偶性,分别加到两人的总数目中,最后比较大小就行了。
附上主要代码:
int T = in.nextInt();
while(T-->0)
{
int n = in.nextInt();
long sum1 = 0;
long sum2 = 0;
for(int i = 0; i< n;i ++)
{
long k = in.nextLong();
if(k%2==1)
sum1 += k;
else sum2 += k;
}
out.println(sum2>sum1?"YES":"NO");
}
C: Find and Replace
https://codeforc.es/contest/1807/problem/C
题意:给定一个字符串每次改变出现的所有某种字符,使它变为0或1,询问能不能是最后更改的字符串变为交替的01串
例如,考虑字符串abacaba。您可以执行以下动作:
将a替换为0。现在字符串为0b0c0b0。
将b替换为1。现在字符串是010c010。
将c替换为1。现在字符串是0101010。这是一个交替的二进制字符串。
题解:我们会发现,每一次都会改变相同的字符串,那么间断出现01的位置就不能出现相同的字符,因为同时改变的过程它们始终相同,不能使它们变得不一样,始终会出现00或11的情况,那么只需要判断这一点就能确定是否能够继续改变了。同时我们可以发现,如果一个字符在奇数位置出现,那么偶数位置就绝对不能是该字符,同理奇数位置出现时也一样。
测试用例:
8
7
abacaba
2
aa
1
y
4
bkpt
6
ninfia
6
banana
10
codeforces
8
testcase
输出用例:
YES
NO
YES
YES
NO
YES
NO
NO
附上代码:
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
int T = in.nextInt();
while(T-->0)
{
int n = in.nextInt();
char[] s = in.next().toCharArray();
int f = 0;
int[] cnt = new int[26];//用cnt数组统计每个字符出现的位置
for(int i = 0;i < n;i ++)
{
int k = s[i] -'a';
if(cnt[s[i]-'a'] != 0)
{
if(cnt[k] == 3 && i %2 ==0)
{
f = 1;//如果这个字符在奇偶数位置同时出现那么不能组成
break;
}
else if(cnt[k] == 2 && i %2 ==1)
{
f = 1;//如果这个字符在奇偶数位置同时出现那么不能组成
break;
}
}
//该字符没有出现过时默认为0
if(i%2==0)
cnt[k] = 2;//如果该字符在偶数位置出现则为2
else cnt[k] = 3;//如果该字符出现在奇数位置出现过就为3
}
out.println(f==1?"NO":"YES");
}
out.flush();
}
}
class InputReader {
private final BufferedReader buf;
private StringTokenizer tkl;
public InputReader(InputStream is) {
buf = new BufferedReader(new InputStreamReader(is));
}
public boolean hasNext() {
try {
while (tkl == null || !tkl.hasMoreElements()) tkl = new StringTokenizer(buf.readLine());
} catch (Exception e) {
return false;
}
return true;
}
public String next() {
return hasNext() ? tkl.nextToken() : null;
}
public int nextInt() {
return Integer.parseInt(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
D:Odd Queries--前缀和
https://codeforc.es/contest/1807/problem/D
题意:每次进行T次询问,每次询问给定一段数组,然后在进行q次询问,每次更改l到r的数组的值为k,询问更改之后数组的元素和是否为奇数,如果是奇数输出“YES”否则输出“NO”。
题解:可以按照题目意思进行模拟修改过程,最后求出元素和进行判断是否为奇数即可。但是我们发现此题的数据n和q的范围都是2*10^5,如果直接暴力模拟那么可能是会TLE的,重新观察本题,我们会发现区间修改数组元素值求和,很符合”前缀和“算法的特征,于是我们就可以用前缀和预处理,后用(O1)的时间复杂度度求出一段区间的和,那么我们算修改后的值就可以为sum - sum[r]+sum[l-1]+(r-l+1)*k,就可以直接判断了,注意为了使边界问题不在困扰,我们把下标使之从1
开始。
附上代码:
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
int T = in.nextInt();
while(T-->0)
{
int n = in.nextInt();
int q = in.nextInt();
int[] arr = new int[n+10];
long[] sum = new long[n+10];
for(int i = 1;i <= n;i ++)
{
arr[i] = in.nextInt();
sum[i] = sum[i-1] + (long)arr[i];//预处理前缀和
}
while(q-->0)
{
int l = in.nextInt();
int r = in.nextInt();
int k = in.nextInt();
long res = 0;
res =sum[n] - sum[r] + sum[l-1];
res += (long)(r-l+1)*(long)k;
out.println(res%2==0?"NO":"YES");
}
}
out.flush();
}
}
class InputReader {
private final BufferedReader buf;
private StringTokenizer tkl;
public InputReader(InputStream is) {
buf = new BufferedReader(new InputStreamReader(is));
}
public boolean hasNext() {
try {
while (tkl == null || !tkl.hasMoreElements()) tkl = new StringTokenizer(buf.readLine());
} catch (Exception e) {
return false;
}
return true;
}
public String next() {
return hasNext() ? tkl.nextToken() : null;
}
public int nextInt() {
return Integer.parseInt(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
G1、G2: Subsequence Addition--排序+贪心
https://codeforc.es/contest/1807/problem/G2
注:G1G2是同一题,只不过改了数据,G2数据较大,为避免爆int我们需要
开Long。
题意:数组初始值为1且长度为1,每次通过加任意长度的子数组之和,将所得数字加入到数组当中。
给定一串数组,询问是否能由初始数组每次更改得到,若能等到输出”YES“,若不能输出”NO“。
题解:数组每次增加的元素必定是子数组的元素和,那么,每次增加的元素总和不应该超过最长的子数组元素和,通过这点我们就可以通过排序得到前面最长子数组的和,并判断即将增加元素是否能被得到(即前m项和是否会小于第i个即将增加的数)
附上代码:
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
public class Main {
static Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static void fun()
{
int n = in.nextInt();
long[] arr = new long[n];
for(int i = 0;i < n;i ++) arr[i] = in.nextLong();
Arrays.sort(arr);
if(arr[0] != 1 )
{
out.println("NO");
return;
}
long sum = 1;
for(int i = 1;i < n;i ++)
{
if(arr[i] > sum)
{
out.println("NO");
return;
}
sum += arr[i];//计算前面最长子数组的和
}
out.println("YES");
}
public static void main(String[] args) {
int T = in.nextInt();
while(T-->0)
{
fun();
}
out.flush();
}
}
总结:
div4还是这么简单,对于像我一样刚入门的算法新手来说很友好,表示很有参与感,e题的交互我是从来没有接触过,时间太晚,f题也没有精力模拟了。我的第一篇博客就写入到这里,希望路过的能给个赞给点鼓励,没有写文经验,希望写的能有进步!