Codeforces Round 835 (Div. 4) E. Binary Inversions
链接: https://codeforces.com/contest/1760/problem/E
题目内容:
题目大意:
给定一个数组里面只含有 1 或 0 ,最多只能改变一次,将数组中的 0 换成 1 或者,将 1 换成 0 。
并找出,数组中满足 i < j 且ai > aj 的个数。
如果要满足题目要求,我们先要考虑一下最优的方法,是不是可以把数组看做两部分,尽量让所有的1在左半边,所有的0在右半边,也就是说:
定义数组,从头往后遍历,如果遇到 0,把它变成 1(范围就是左半边)
再定义一个数组,从后往前遍历,如果遇到 1,把它变成 0 (范围就是右半边)
然后循环套循环求出个数,比大小即可
但是写完代码提交会出现超时的情况。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
int a[n+1];
int b[n+1];
int flaga = 0;
for(int i = 1;i<=n;i++)
{
int x;cin>>x;
a[i] = x;//两个数组分别存放数值
b[i] = x;
}
//从前往后遇到 0 跳出结束,从后往前遇到 1 结束
for(int i = 1;i<=n/2;i++)
{
if(a[i] == 0)
{
a[i] = 1;
break;
}
}
for(int i = n;i>n/2;i--)
{
if(b[i] == 1)
{
b[i] = 0;
break;
}
}
int suma = 0;
for(int i = 1;i<n;i++)
{
for(int j = i+1;j<=n;j++)
{
if(a[i]>a[j])
{
suma++;
}
}
}
int sumb = 0;
for(int i = 1;i<n;i++)
{
for(int j = i+1;j<=n;j++)
{
if(b[i]>b[j])
{
sumb++;
}
}
}
int maxc = max(suma,sumb);
cout<<maxc<<endl;
}
return 0;
}
所以要进一步的优化,我们能不能将时间复杂度变为线性?
如果我们在从前往后遍历和从后往前遍历的时候,分别存储 0 的个数,再在最后循环判断个数的时候,如果遇到1,我们就让直接加上 0 的个数,如果遇到 0 ,我们就让0的个数减1。
这样会不会降低时间复杂度呢?
我们不妨来试试:
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
int c[n+1],a[n+1],b[n+1];
for(int i = 1;i<=n;i++)
{
cin>>c[i];
b[i] = c[i];
a[i] = c[i];
}
int suma = 0,flaga = 0;//sum表示0的个数,flag表示更改后进行标记
int sumb = 0,flagb = 0;
for(int i = 1,j = n;i<=n,j>0;i++,j--)
{
if(a[i] == 0 && i<=n/2 && flaga == 0)
{
flaga = 1;
a[i] = 1;
}
if(a[i] == 0)
suma++;
if(b[j] == 1 && j>n/2 && flagb == 0)
{
flagb = 1;
b[j] = 0;
}
if(b[j] == 0)
sumb++;
}
int zongshua = 0;
int zongshub = 0;
for(int i = 1;i<=n;i++)//一个循环就可以确定个数
{
if(a[i] == 1)
{
zongshua+=suma;
}
else
{
suma--;
}
if(b[i] == 1)
{
zongshub+=sumb;
}
else
{
sumb--;
}
}
cout<<max(zongshua,zongshub)<<endl;
}
return 0;
}
对啦!