首页 > 其他分享 >减法操作

减法操作

时间:2022-09-25 14:12:04浏览次数:75  
标签:奇数 一个 元素 偶数 操作 减法 执行

减法操作

给定一个包含 $n$ 个非负整数的数列 $a_1,a_2, \dots ,a_n$。

你可以对该数列进行以下两种减法操作:

  • 任选其中一个元素,并将该元素的值减去 $2$。
  • 任选两个相邻元素,并将两个元素的值各减去 $1$。

请你判断,能否经过一系列减法操作,使得数列中的所有元素都变为 $0$。

输入格式

第一行包含整数 $n$。

第二行包含 $n$ 个非负整数 $a_1,a_2, \dots ,a_n$。

输出格式

如果能够经过一系列减法操作,使得数列中的所有元素都变为 $0$,则输出 YES ,否则输出 NO 。

数据范围

前 $6$ 个测试点满足 $1 \leq n \leq 10$。
所有测试点满足 $1 \leq n \leq 2 \times {10}^{5}$,$0 \leq a_i \leq {10}^{4}$。

输入样例1:

4
1 2 1 2

输出样例1:

YES

输入样例2:

3
1 0 1

输出样例2:

NO

 

解题思路

  比赛的时候想到的思路是,既然要求最后整个序列的每个数都变成$0$,那么就构造出一种方案,看看能不能让每个位置上的数都变成$0$。从前往后遍历每一个数,如果这个数是偶数,那么只进行操作$2$就可以。如果这个数是奇数,那么至少要执行一次操作$1$,这里就规定每次执行操作$1$时都是与当前位置的下一个位置减$1$,且对该数只执行一次操作$1$,剩下的都执行操作$2$(如果是序列的最后一个数,由于没有下一位了,因此如果最后一个数是奇数,那么就不可以执行任何操作了,即无法将序列变成全$0$)。最后看一下每一个位置是否都是非负数并且都是偶数就可以了。

  补一下y总严格的证明。

  我们将所有的操作方案看作是一个集合,现在考虑一下最优解有什么性质,看能不能在一个子集中找到答案。首先操作顺序并不会影响结果,比如对于一个数,先减$2$再减$1$,或者是先减$1$再减$2$都不会影响这个数的最终结果。因此我们可以人为定义一个操作顺序,就是先执行所有的操作$2$再去执行操作$1$,我们就可以在这个子集中看一下是否存在一种方案使得序列变成$0$。同时对于相邻的两个数,如果这两个数执行了两次操作$2$,那么等价于这两个数分别执行一次操作$1$,因此在这个子集中我们还可以考虑另外一个子集,在这子集中同一对元素只会执行一次操作$2$,因此最终我们只需要在这个子集的子集里面考虑就可以了,如果这个子集中存在某个方案使得序列变成$0$,那么代价于执行完所有的操作$2$后所有元素都变成非负偶数才可以。

  我们可以从前往后找到第一个奇数,由于要变成偶数,那么就要对这个数执行操作$2$,有两种选择,要么与这个数后面一个数执行操作$2$,要么与这个数前面一个数执行操作$2$。如果是与这个数前面一个数执行操作$2$,由于前面这个数是偶数,因此操作完后就变成奇数,由于要变成偶数,因此也有两种选择,与后面一个数或者与前面一个数执行操作$2$。如果是选择后面一个数,那么相当于相邻的两个元素执行了两次操作$2$,而这种方案不在这个子集中,因此只能选择前面的数。以此类推,前面的数又从偶数变成奇数了,那么总是与前一个数执行操作$2$,直到是序列的第一个元素,第一个数变成奇数,此时它前面没有元素了,就无法执行操作$2$,也不能与后面一个数执行操作$2$,因此就无解了。因此我们从前往后枚举找到第一个奇数后,我们只能操作这个数和它后面一个数,所以操作方案是唯一的。

  如果从前往后枚举找到某个数是偶数,要么不执行操作$2$,要么执行两次操作$2$,并且这两次操作$2$分别是选择前面一个数和后面一个数。而与前面一个数执行完操作$2$后,前面那个数就变成奇数了,那么又要对前面这个数执行操作$2$,可以发现又变成上面所描述的无解的情况了。因此如果遇到偶数,我们不能进行操作$2$。

  因此如果遇到奇数我们只能操作这个数和它后面一个数,如果数偶数我们不能操作。所以操作方案是唯一确定的。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2e5 + 10;
 5 
 6 int a[N];
 7 
 8 int main() {
 9     int n;
10     scanf("%d", &n);
11     for (int i = 0; i < n; i++) {
12         scanf("%d", a + i);
13     }
14     
15     bool flag = true;
16     for (int i = 0; i < n; i++) {
17         if (a[i] < 0) { // 每个数要求是非负偶数
18             flag = false;
19             break;
20         }
21         if (a[i] & 1) { // 奇数
22             if (i == n - 1) flag = false;   // 最后一个数是奇数,而最后一个数后面没有数,无法执行操作2
23             a[i + 1]--; // 与后面一个数执行操作2
24         }
25     }
26     
27     printf("%s", flag ? "YES" : "NO");
28     
29     return 0;
30 }

 

参考资料

  AcWing 4619. 减法操作(AcWing杯 - 周赛):https://www.acwing.com/video/4405/

标签:奇数,一个,元素,偶数,操作,减法,执行
From: https://www.cnblogs.com/onlyblues/p/16727282.html

相关文章

  • Redis 基本操作
    字符串(Strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sortedsets)......
  • jquery判断select中是否存在某个value以及进行增加、删除操作
    一、判断select中是否存在值为value的项functionisExistOption(id,value){varisExist=false;varcount=$('#'+id).find('option').length;......
  • c#常用的文本操作
    1.从index截取到字符串结束:string.Substring(index) 2.从index截取length长度的字符串:string.Substring(index,length)3.查找字符串最先出现的index://如果......
  • acwing 4619. 减法操作
    acwing4619.减法操作原题链接:https://www.acwing.com/problem/content/4622/思路这个题两种操作顺序是先进行哪个操作都是可以的。第一个操作将某个数减2,只要是偶数就......
  • Java8 提供的流式操作
    目录参考资料流式操作1.java.util.stream.Stream接口1.1Stream提供的方法2.Collection的流式操作参考资料https://docs.oracle.com/javase/8/docs/api/流式操作......
  • Vim常用操作
    目录基本概念编辑浏览命令行模式总结基本概念vim有三种工作模式:一般模式:vimfile之后就进入了一般模式编辑模式:一般模式下按i、a、o等,按Esc返回一般模式修改文件的......
  • 隐藏若依框架侧边栏、导航栏、右上角操作按钮,实现全屏显示
    1.隐藏侧边栏、导航栏    将上图所注释掉的代码注释即可隐藏侧边栏、导航栏。2.隐藏右上角操作按钮,   将上图所注释掉的代码注释即可隐藏右上方图案。......
  • SQLYOG基本命令行操作
    DOS窗口: 连接数据库:命令行连接:mysql-uroot-p刷新权限:flushprivileges查看所有的数据库:showdatabases;切换数据库:use数据库名查看数据库中所有的表:......
  • TypeScript Array数组 生成两个数组的交集,并且在数组中进行删除操作
    TypeScriptArray数组 生成两个数组的交集,并且在数组中进行删除操作 /***@methodcutArr删除数组1中,与数组2重复的数据*Arr([1,2,3,5],[2,3,4])=>[1,5......
  • mysql 更换root密码简单操作
    usemysql;--切换数据库--更新密码updateusersetauthentication_string=password('123456')whereuser='root'; --刷新权限等信息flushprivileges; 执行......