题干:
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个长度为N的数组A1, A2, ... AN,请你判断其中有几个元素Ai按如下跳跃规则能跳到最后一个元素AN。
假设你当前位于Ai,跳跃的规则是:
如果这一步是第奇数次跳跃(从1开始计数),可以跳到Ai之后(Ai+1 .. AN)比Ai大的最小的元素;
如果这一步是第偶数次跳跃,可以跳到Ai之后(Ai+1 .. AN)比Ai小的最大的元素;
如果有多个满足条件的元素,则跳到其中下标最小的元素。
如果没有满足条件的元素,则在当前的Ai停下来。
例如对于A = [3, 2, 4, 1, 5],如果从3开始,第一步从3跳到4,第二步从4跳到1,第三步从1跳到5。
输入
第一行包含一个整数N。
第二行包含N个整数A1, A2, ... AN。
对于30%的数据,1 <= N <= 100
对于60%的数据,1 <= N <= 1000
对于100%的数据,1 <= N <= 100000 1 <= Ai <= 1000000
输出
一个整数代表答案
样例输入
5
3 4 1 2 5
样例输出
4
解题报告:
先用set倒着扫一遍数组,顺便预处理出距离最近的比他大的最小的数的下标,和距离最近的比他小的最大的数的下标,这一步可以用单调栈O(n)实现,但是因为时间允许于是set好写一些。然后dp代表从编号i开始的第偶数/奇数步,能不能到达最后。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#include<cctype>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 2e6 + 5;
set<int> ss;
bool dp[MAX][2];
int big[MAX],small[MAX],pos[MAX],a[MAX];//预处理出后面第一个比他大的和第一个比他小的
int main() {
int n;
cin>>n;
for(int i = 1; i<=n; i++) scanf("%d",a+i);
for(int i = n; i>=1; i--) {
if(ss.count(a[i])) pos[a[i]] = i;
else ss.insert(a[i]),pos[a[i]] = i;
auto it = ss.upper_bound(a[i]);
if(it != ss.end()) big[i] = pos[*it];
else big[i] = -1;
it = ss.lower_bound(a[i]);
if(it == ss.begin()) small[i] = -1;
else {
--it;
small[i] = pos[*it];
}
}
// for(int i = 1; i<=n; i++ ) {
// printf("i: %d : %d %d\n",i,big[i],small[i]);
// }
dp[n][0] = 1,dp[n][1] = 1;
for(int i = n-1; i>=1; i--) {
if(big[i] != -1) dp[i][1] = dp[big[i]][0];
if(small[i] != -1) dp[i][0] = dp[small[i]][1];
}
int ans = 0;
for(int i = 1; i<=n; i++) {
if(dp[i][1]) ans++;
}
printf("%d\n",ans);
return 0 ;
}
注意因为题中的大于和小于都是严格大于和严格小于,所以判断大于必须用upper,否则可能set中已经有一个a[i]了,,你再lower就肯定不对了。
同样的,也可以用map实现:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+55;
int dp[N][2];
int a[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i];
map<int,int> mp;
map<int,int> ::iterator it;
mp[a[n]] = n;
dp[n][1] = 1;
dp[n][0] = 1;
for(int i=n-1;i>0;--i)
{
it = mp.lower_bound(a[i]);
if(it==mp.end()||it==mp.begin())
dp[i][0] = 0;
else dp[i][0] = dp[(--it)->second][1];
it = mp.upper_bound(a[i]);
if(it==mp.end()) dp[i][1] = 0;
else dp[i][1] = dp[it->second][0];
mp[a[i]]=i;
}
int ans = 0;
for(int i=1;i<=n;++i)
{
if(dp[i][1]) ans++;
}
cout<<ans;
return 0;
}