• 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;
        }
    }
  • 相关阅读:
    js对象数组(JSON) 根据某个共同字段 分组
    ajax如何处理服务器返回的三种数据类型
    JavaScript中常见排序算法详解
    《JavaScript语言精粹》读书笔记——给类型增加方法一节的疑问
    前端常见跨域解决方案(全)
    ACE模板的布局简介
    ES6学习笔记---对象的扩展
    偏振
    欧拉赞词
    狄拉克δ函数的导数
  • 原文地址:https://www.cnblogs.com/Saurus/p/6222441.html
Copyright © 2020-2023  润新知