算法沉淀第一天(Triple Removal)
目录
引言:
Triple Removal
题意分析
逻辑梳理
代码实现
结语:
引言:
家人们,天塌了,速通ACM省铜失败了,只能沉淀算法了,来年再战,接下来,C语言专栏的更新就恢复照常了
今天是算法沉淀的第一天,先开个CF评级1400的题热热手,那么,我们废话不多说,就进入今天的题目讲解吧——————————>
Triple Removal
那么,按照先前惯例
题意分析
这是题目链接Problem - 2152C - Codeforces
不想跳转的可看下图
这道题的意思很简单,就是给你一个数组,然后数组里面的元素不是1就是0
然后再问你q次,每次问你从l到r的那一段数组可不可以通过操作来将这一块数组清空
然后如果可以,就输出最小的操作代价
如果不可以,就输出-1
然后具体每次怎么操作呢
1.先选择3个下标i,j,k,这三个下标所对应的元素值要一样
2.删除这三个元素,付出的操作代价是min(k-j,j-i),然后将删完数的数组再合并起来,不留空隙
那么,题目分析完了,接下来就进入逻辑梳理环节
逻辑梳理
这题的逻辑其实还是比较好梳理的,一步步来就好了
首先,如果这个数组区间的长度不是3的倍数,那么肯定输出-1,因为每次选择删除的个数都要为3个
那么接下来接着想,还有什么情况会输出-1呢,那就是这个区间的数组中,1的个数或是0的个数不为3的倍数,因为每次要删的都是3个一样的数,所以如果1的个数和0的个数不是 3的倍数,那么就无法将所有数删完
那么,接下来,不能删完的情况判断完了,接下来我们来判断能删完的情况下,最少的代价怎么算
首先,因为他每次删除3个后都会压缩数组,所以,如果一开始有俩个一样的数相邻,就一定可以每次都进行1的损耗就删除3个元素
而如果一开始没有俩个一样的数相邻,那么就只有01010101或者101010的情况,所以就是第一次删除的时候需要2的代价,之后也是1的代价
那么逻辑梳理就梳理完啦,接下来进入代码实现的环节
代码实现
首先,代码实现过程中需要3个数组来分别存放0的个数的前缀和和1的个数的前缀和和相邻元素是一样的前缀和,如果不用这三个前缀和数组来进行存放,那么就会超时,我第一发就是因为没有相邻数的前缀和数组,导致代码TLE了,那么,接下来,就直接展现AC源码啦
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;int t, n;
bool a[250010];
int zero[250010];
int one[250010];
int ling[250010];
void solve()
{int l, r;cin >> l >> r;if ((zero[r] - zero[l - 1]) % 3 || (one[r] - one[l - 1]) % 3){cout << "-1" << endl;return;}int ans = 1;if (ling[r]-ling[l]){ans--;}ans += (r - l + 1) / 3;cout << ans << endl;
}int main()
{cin >> t;while (t--){memset(one, 0, sizeof(one));memset(zero, 0, sizeof(zero));memset(ling, 0, sizeof(ling));int q;cin >> n >> q;a[0] = -1;for (int i = 1; i <= n; i++){cin >> a[i];if (a[i]){one[i] = one[i - 1] + 1;zero[i] = zero[i - 1];}else{one[i] = one[i - 1];zero[i] = zero[i - 1] + 1;}if (a[i] == a[i - 1])ling[i] = ling[i-1] + 1;elseling[i] = ling[i-1];}while (q--)solve();}return 0;
}
结语:
今日算法讲解到此结束啦,希望对你们有所帮助,谢谢观看,如果觉得不错可以分享给朋友哟。有什么看不懂的可以评论问哦,这是真的最后一期啦