加油 ( •̀ ω •́ )y!

51nod 1281山峰和旗子

题目来源: Codility
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
用一个长度为N的整数数组A,描述山峰和山谷的高度。山峰需要满足如下条件, 0 < P < N - 1 且 A[P - 1] < A[P] > A[P + 1]。
 
 
现在要在山峰上插上K个旗子,并且每个旗子之间的距离 >= K,问最多能插上多少个旗子(即求K的最大值)。两个山峰之间的距离为|P - Q|。
以上图为例,高度为:1 5 3 4 3 4 1 2 3 4 6 2。其中可以作为山峰的点为:1 3 5 10。
 
放2面旗子, 可以放在1 和 5。
放3面旗子, 可以放在1 5 和 10。
放4面旗子, 可以放在1 5 和 10,之后就放不下了。
所以最多可以放3面旗子。
Input
第1行:一个数N,表示数组的长度(1 <= N <= 50000)。
第2 - N + 1行:每行1个数Ai(1 <= Ai <= 10^9)。
Output
输出最多能插上多少面旗子(即求K的最大值)。
Input示例
12
1 
5 
3 
4 
3 
4 
1 
2 
3 
4 
6 
2
Output示例
3

思路:二分+dp-------用一个f[]数组保存山峰的位置,首先如果没有山峰则直接输出0,其次距离越大代表我们要插的旗子数就越大,我们枚举旗子的个数k 找到最大的可行方案;当然直接枚举会超时,所以这里需要用二分来枚举;
   对于每一个k我们需要用一次dp数组来遍历一次,dp[i]代表前i个位置能插入距离为k的旗子的个数;我们可以得到递推公式 若当前位置不可以插旗子dp[i] = dp[i-1];否则dp[i] = max(dp[i-k]+1,dp[i]);
   其中i-k>0;遍历完之后若dp[n-1]>=k说明我们的k还可以继续增大,直到dp[n-1]恰好等于k的时候就停止二分,此时的k即为最大值
 
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 using namespace std;
 6 typedef long long LL;
 7 const int maxn = 50005;
 8 LL n,a[maxn],f[maxn],d[maxn];;
 9 int main()
10 {
11     ios::sync_with_stdio(false);
12 //    freopen("in.txt","r",stdin);
13     while(cin>>n){
14         int flag = 0;
15         for(int i=0;i<n;i++)cin>>a[i];
16         for(int i=1;i<n-1;i++)
17             if(a[i]>a[i-1]&&a[i]>a[i+1]){
18                 f[i] = 1;flag++;
19             }
20         if(!flag){
21             cout<<"0"<<endl;
22             continue;
23         }
24         int l=0,r=n,ans=0;
25         while(l<r){
26             int k = (l+r)>>1;
27             for(int i=0;i<n;i++)
28                 d[i] = f[i];
29             for(int i=0;i<n;i++){
30                 if(!f[i])d[i]=d[i-1];
31                 else if(i-k>0) d[i] = max(d[i-k]+1,d[i]);
32             }
33             if(d[n-1]>=k){
34                 ans = k;
35                 l = k+1;
36             }else r = k;
37         }
38         cout<<ans<<endl;
39     }
40     return 0;
41 }

 

 

posted @ 2018-08-06 21:05  皮皮虎  阅读(241)  评论(0编辑  收藏  举报