题目概述:给一个只含零一的数组。我们可以选择数组内的任意元素,至多执行下列操作一次。(只能选择一个元素执行操作)。操作为:反转你选择的元素(1变为0,0变为1)。
求操作后(可以不执行),数组里能得到的符合下列情况(且)的组合的数量。
思路:
先处理出每个元素前边有多少个一,后边有多少个零(自身为一或零算上自身)可以用pair来存。前一后零即为符合条件的情况。
这样我们就可以根据每一个一以及它后面的零的个数(根据零道理一样)来求在执行操作前符合条件的组合数量sum。
假设我们要执行操作,我们可以遍历每个元素,求得变化后带来的增量(可能为负增量)的最大值max。具体为:我们令 first为 a[i] 的前缀1的个数,second为后缀的0的个数。对于1变成0,我们的增量为first - 1 -second;对于0 变为 1,我们的增量为 second - 1 - first。
最后sum减去max即为答案。
注意数据范围,sum 记得开long long
代码:
#include <bits/stdc++.h>
using namespace std;
const int N =2e5+10;
int a[N];
pair<int,int>c[N];
void solve()
{
int n;
cin >> n;
for(int i = 0;i < n;i++)
{
cin >> a[i];
}
int one = 0,zero = 0;
for(int i = 0,j = n - 1;i < n&&j >= 0;i++,j--)
{
if(a[i])
{
one ++;
}
if(!a[j])
{
zero ++;
}
c[i].first = one;//每个元素前面有多少个一
c[j].second = zero;//每个元素后边有多少个零
//若自身为一或零,也算上自身
}
long long sum = 0;
for(int i = 0;i < n;i++)
{
if(a[i]) sum += c[i].second;//对于每一个一来求和他匹配的零个数
//和就是操作前的匹配数
}
long long max = 0;
for(int i = 0;i < n;i++)//求进行一次操作后能得到的最增量
{
if(a[i])
{
int t3 = c[i].first - 1 - c[i].second;
if(max < t3)
{
max = t3;
}
}
else
{
int t3 = c[i].second- 1 - c[i].first;
if(max < t3)
{
max = t3;
}
}
}
sum += max;//操作后得到答案为和加上增量
cout << sum <<"\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
cin >> t;
while(t--)
{
solve();
}
return 0;
}