• 51nod 1281 二分+DP


    题意:n个数字,只有既大于左边又大于右边的数字是山顶,要在山顶上插k面旗子,相邻旗子的距离>=k,最大化k

    数据范围: n <= 50000

    思路:最大化最小值,显然是二分,重点在如何写check函数

    首先肯定是把所有山顶标记起来,设dp[i]为前i个点最多插多少旗子

    然后:1.对于一个山顶 dp[i] = max(dp[i], dp[i-k]+1)  插旗子

    2. 对于一个不是山顶 dp[i] = max(dp[i], dp[i-1]) 继承前面的值

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #define LL long long
     6 #define debug(x) cout << "[" << x << "]" << endl
     7 using namespace std;
     8 
     9 const int mx = 50010;
    10 int dp[mx], n, a[mx];
    11 bool vis[mx];
    12 
    13 bool check(int k){
    14     memset(dp, 0, sizeof dp);
    15     if (k == 1){
    16         for (int i = 1; i <= n; i++)
    17             if (vis[i]) return 0;
    18         return 1;
    19     }
    20     for (int i = 2; i <= n-1; i++){
    21         dp[i] = vis[i];
    22         if (!vis[i]) dp[i] = max(dp[i-1], dp[i]);
    23         else if (i >= k) dp[i] = max(dp[i], dp[i-k]+1);
    24     }
    25     return dp[n-1] < k;
    26 }
    27 
    28 int main(){
    29     scanf("%d", &n);
    30     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    31     for (int i = 2; i <= n-1; i++){
    32         if (a[i] > a[i-1] && a[i] > a[i+1])
    33             vis[i] = 1;
    34     }
    35     int l = 1, r = n;
    36     while (l <= r){
    37         int mid = (l+r)>>1;
    38         if (check(mid)) r = mid-1;
    39         else l = mid+1;
    40     }
    41     printf("%d
    ", r);
    42     return 0;
    43 }
  • 相关阅读:
    旧文备份:CANopen协议PDO的几种传输方式
    CANopen 基础
    单片机FLASH与RAM、ROM的关系
    在CANopen网络中通过LSS服务设置节点地址和网络波特率
    STM32F103 CAN中断发送功能的再次讨论
    由RS-232串口到PROFIBUS-DP总线的转换接口设计
    profibus 的DPV0 和DPV1
    PROFIBUS-DP
    profibus总线和profibus dp的区别
    获取验证码倒计时
  • 原文地址:https://www.cnblogs.com/QAQorz/p/9620954.html
Copyright © 2020-2023  润新知