51nod 1281山峰和旗子
用一个长度为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 }