[思维]Kobolds and Catacombs 第45届icpc区域赛沈阳站F

59 篇文章 0 订阅

题目描述

Kobolds are rat-like, candle-loving cave folk, digging deep beneath the surface for millennia. Today, they gather together in a queue to explore yet another tunnel in their catacombs!
But just before the glorious movement initiates, they have to arrange themselves in non-descending heights. The shortest is always the leader digging small holes, and the followers swelling it.
The kobolds are hyperactive; they like to move here and there. To make the arrangement easier, they decide to group themselves into consecutive groups first, then reorder in each group.
What's the maximum number of consecutive groups they can be partitioned into, such that after reordering the kobolds in each group in non-descending order, the entire queue is non-descending?
For example, given a queue of kobolds of heights [1,3,2,7,4]{[1, 3, 2, 7, 4]}[1,3,2,7,4], we can group them into three consecutive groups ([1][3,2][7,4]{[1] [3, 2] [7, 4]}[1][3,2][7,4]), such that after reordering each group, the entire queue can be non-descending.

输入描述:

The first line of the input contains a single integer n{n}n (1≤n≤106)(1 \le n \le 10^6)(1≤n≤106), denoting the number of kobolds. The second line contains n{n}n integers a1,a2,…,ana_1, a_2, \ldots , a_na1​,a2​,…,an​ (1≤ai≤109)(1 \le a_i \le 10^9)(1≤ai​≤109), representing the heights of the kobolds in the queue.

输出描述:

Print a single integer, denoting the maximum number of groups.

示例1

输入

5
1 3 2 7 4

输出

3

题意: 有一个长度为n的序列,可以将序列分为m段,每段内部自动升序排序,求要使整个序列变成升序能够分的最多段数。

分析: 由于段与段之间不能够重叠,相当于每段只能被排序一次,在经过这次排序后其顺序就不可更改了,也就是整个序列排完序局部的样子了。因此可以求出每个数字在最终有序序列中的位置,保存在数组rk[]中,从序列左端点开始动态维护一个区间max,值为max(rk[1]~rk[i]),如果max等于i,那么就可以从这里分段,同时令ans++,模拟几组数据可以发现这是十分显然的。

唯一需要注意的地方是序列中可能出现的重复数值,实际上相同的数字也会排出个先后的,令最先出现的数字排在前面即可,因为这样是最优的(显然这样可以使每段长度尽可能小),实现上只需要lower_bound得到的值再加上这个值之前出现次数作为其排名。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

int a[1000005];//原数组 
int sorted[1000005];//排序过后的数组
int rk[1000005];//名次数组 
int mp[1000005];//某名次出现次数 

signed main()
{
	int n;
	cin >> n;
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i]); 
		sorted[i] = a[i];
	}
	sort(sorted+1, sorted+1+n);
	for(int i = 1; i <= n; i++)
	{
		int t = lower_bound(sorted+1, sorted+1+n, a[i])-sorted;
		rk[i] = t;
		rk[i] += mp[t];
		mp[t]++; 
	}
	int _max = 0, ans = 0;
	for(int i = 1; i <= n; i++)
	{
		_max = max(_max, rk[i]);
		if(_max == i)
			ans++;
	}
	cout << ans;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值