zoukankan      html  css  js  c++  java
  • Codeforces Round #389 (Div. 2) 752E(二分答案)

    题目大意

    可以理解成有n个木板,可以选取木板将其劈成2半(如果长度是奇数,就切成x和x+1),切完之后还可以再切

    然后你要把这n个木板切成更多的木板,然后从中选择k个,使得这k个木板的最小长度尽量大

    这个题有两种做法,不过都需要二分答案

    先二分最小长度是x

    第一种做法是 枚举n个木板,每一个都切到不能再切为止,然后统计有多少个木板,看能否符合

          统计过程中要记录两个值,因为一个木板不论切多少次,结果都只会存在两种木板,然后记录一下每次切是哪两种木板以及各有多少个,然后简单转移即可

          复杂度是nlog^2c

    第二种做法是 类似dp的做法,dp[i]表示长度为i的木板有多少个,那么转移很简单,如果(i+1)/2仍不小于x,那么可以转移到dp[(i+1)/2]和dp[i/2]

          最后统计i大于x的dp[i]的值即可

          复杂度是clogc

    一开始写的第一种做法,常数写渣了,TLE,好气啊orz

    还是第二种做法比较神奇

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    using namespace std;
    typedef long long LL;
    int n, k;
    int a[1000001];
    LL dp[10000002];
    bool can(int x)
    {
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < n; i++) dp[a[i]]++;
        LL ans = 0;
        for(int i = 10000001; i >= max(x, 2); i--)
        {
            if(dp[i])
            {
                if((i+1)/2 >= x)
                {
                    dp[i/2] += dp[i];
                    dp[(i+1)/2] += dp[i];
                } else
                ans += dp[i];
            }
        }
        if(x == 1) ans += dp[1];
        return ans >= k;
    }
    
    int main()
    {
        cin>>n>>k;
        for(int i = 0; i < n; i++) scanf("%d", &a[i]);
        int l = 1, r = 1e7;
        while(l+1 < r)
        {
            int mid = (l+r)>>1;
            if(can(mid)) l = mid;
            else r = mid;
        }
        if(!can(1)) cout<<"-1"<<endl;
        else
        {
            if(can(l+1)) cout<<l+1<<endl;
            else cout<<l<<endl;
        }
    }
  • 相关阅读:
    手把手教你封装属于自己的分段滚动视图(上)
    从 setNeedsLayout 说起
    cocoapods使用指南
    神奇的 BlocksKit(1):源码分析(下)
    Web应用开发中的几个问题
    Jquery Ajax自定义无刷新提交表单Form
    解耦HTML、CSS和JavaScript
    通过预加载器提升网页加载速度
    巧妙使用CSS创建可以打印的页面
    有用的JavaScript开发小建议
  • 原文地址:https://www.cnblogs.com/Saurus/p/6222441.html
Copyright © 2011-2022 走看看