非零段划分(CSP202109-2)

非零段划分

题目链接

题目描述:
在这里插入图片描述

输入格式:
在这里插入图片描述

输出格式:
在这里插入图片描述


样例1:
输入:

11
3 1 2 0 0 2 0 4 5 0 2

输出:

5

样例2:
输入:

14
5 1 20 10 10 10 10 15 10 20 1 5 10 15

输出:

4

样例3:
输入:

3
1 0 0

输出:

1

样例4:
输入:

3
0 0 0

输出:

0

分析:首先暴力肯定是会超时的O(n^2).在没有找出规律(或者毫无规律可言)的情况下,借助C++ STL优化算法对于降低时间复杂度来说是非常有效的。

思路:

  1. 首先进行离散化,将题中所给的数据离散化为连续的数据。
  2. 利用vector向量,保存每个数据离散化后的位置(和离散化前位置应该一样)
  3. 从0开始,第一次把0的位置全部变成0(即进行标记);第二次把1的位置全部变成0…依此类推。 细节处理:假设x的位置要变为0,若x-1和x+1的位置均被标记过了,则非零段-1;若都没标记过,则非零段+1;若有其中一个被标记过了,则非零段不变。
  4. 特殊情况: 若数组元素全为0,则ans = 0;

时间复杂度几乎为:O(n)

100分的代码:

#include <bits/stdc++.h>
#include <vector>
#include <set>
#include <algorithm>

#define fi first
#define se second
#define pb push_back

using namespace std;

const int N = 500010;
typedef pair<int,int> PII;
PII a[N];
int b[N];
bool book[N];          // 标记位置
vector<int> vc[N];     // 存放离散后的位置 

int main()
{
    
    
	int n;
	scanf("%d",&n);
    // 离散化 
	for(int i=1;i<=n;i++){
    
    
		scanf("%d",&a[i].fi);
		a[i].se = i;
	}
	sort(a+1,a+n+1);
	
	int pos = 1;
	for(int i=1;i<=n;i++){
    
    
		if(a[i].fi!=a[i-1].fi && i!=1)	pos++;
		
		b[a[i].se] = pos;
	}
//	for(int i=1;i<=n;i++){
    
    
//		printf("%d ",b[i]);
//	}
//	cout << "\n=================================" << endl;

	for(int i=1;i<=n;i++){
    
    
		vc[b[i]].pb(i);
	}
	
//	for(int i=1;i<=pos;i++){
    
    
//		for(int j=0;j<vc[i].size();j++){
    
    
//			cout << vc[i][j] << " ";
//		}
//		cout << endl;
//	}
//	cout << "=================================" << endl;

	book[0] = 1,book[n+1] = 1;
	int ans,res = 1;
	// res 保存上次的结果, backup 保存此次更新的结果 
	for(int i=1;i<=pos;i++){
    
    
		int backup = res;
		
		for(int j=0;j<(int)vc[i].size();j++){
    
    
			int x = vc[i][j];
			
			book[x] = 1;
			
			if(book[x-1] && book[x+1])	backup--;
			else if(!book[x-1] && !book[x+1])	backup++;
		}
		
//		cout << "backup=" << backup  << endl;
		
		ans = max(ans,max(res,backup));
		res = backup;
	}
	
	if(pos==1&&a[n].fi==0)	ans = 0;       // 特殊情况:若数组元素全为0,则ans = 0;
	
	cout << ans << endl;
	
	return 0;
}

注:也可以不使用sort,使用set或者优先队列进行优化.目的是排序

优化版本:时间复杂度和空间复杂度都是最优。

#include <bits/stdc++.h>
#include <vector>
#include <algorithm>

#define pb push_back

using namespace std;

const int N = 500010;
const int M = 10010;
//int a[N]; 
bool book[N];
vector<int> vc[M];     // 存放位置 

int main()
{
    
    
   int n;
   scanf("%d",&n);
   int p;
   for(int i=1;i<=n;i++){
    
    
   	scanf("%d",&p);
   	vc[p].pb(i);
   }

   book[0] = 1,book[n+1] = 1;
   int ans,res = 1;
   // res 保存上次的结果, backup 保存此次更新的结果 
   for(int i=0;i<=10000;i++){
    
    
   	if(!vc[i].size())	continue;
   	int backup = res;
   	
   	for(int j=0;j<(int)vc[i].size();j++){
    
    
   		int x = vc[i][j];
   		
   		book[x] = 1;
   		
   		if(book[x-1] && book[x+1])	backup--;
   		else if(!book[x-1] && !book[x+1])	backup++;
   	}
   	
//		cout << "backup=" << backup  << endl;
   	
   	ans = max(ans,max(res,backup));
   	res = backup;
   }
   
   if(vc[0].size()==n)		ans = 0;
   
   cout << ans << endl;
   
   return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_50435987/article/details/120602998