P9540 题解
思路
刚看到这题,无从下手,怎么办?看看部分分。但是写部分分却对想到正解有作用。
首先,我们看看特殊性质 A。所有数字都 或所有数字都 ,那现在翻转操作是没用的,但题目要求我们要必须刚好操作 次,所以我们只要随便翻转一下,把这 次浪费掉即可。我们对所有数字都 的情况不用操作,输出 ,而对所有数字都 的情况统一做一次变换操作即可,输出 。
我们再看看 的情况。对于每次翻转,我们可以把两块连续的 的部分合并到一起。如果 ,那么所有 的数字将会被合到一起,这样我们只要看是不是所有数字都是 即可,如果是的,那输出 ,否则输出 。
当 时,这时候我们要考虑合并了。要使合并最优,当然是把所有 的数字尽可能放一起,所有 的数字尽可能放一起。只有变换操作,那我们只要把所有 的连续数字块一起变换即可,所以我们只要统计 的连续块个数就好了。
最后,部分分都想完了,正解也就出来了。因为每次翻转操作会把两块 的连续块连一起,连续块个数也就减少了 ,所以正解只要在 的方法的基础上,把 的连续块个数减掉 就好了。需要注意的是,如果把 的连续块个数减掉 后答案不足 了,那这个问题就转化成了 的情况,所以要把答案和 取 。还有,当所有数都是 的时候,我们不需要操作,所以只要输出 就可以了,这个特判一下就好了。
代码
# include <bits/stdc++.h>
using namespace std;
int n, y, z, a[2000005], ans, ans2;
bool f = 1; //记录是否有 != y 的元素
int main () {
cin >> n >> y >> z;
for (int i = 0; i < n; ++ i)
cin >> a[i];
for (int i = 0; i < n; ++ i)
cin >> a[i + n];
for (int i = 0; i < n << 1; ++ i)
if (a[i] != y) {
f = 0;
break ;
}
if (f) { //特判
cout << 0;
return 0;
}
for (int i = 1; i < n; ++ i)
if (a[i] == y && a[i - 1] != y) //算连续块
++ ans;
if (a[n - 1] != y) //最后一个块别忘记
++ ans;
for (int i = n + 1; i < n << 1; ++ i)
if (a[i] == y && a[i - 1] != y)
++ ans2;
if (a[n * 2 - 1] != y)
++ ans2;
cout << max (1, max (ans, ans2) - z); //取个 max
return 0;
}

浙公网安备 33010602011771号