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;
        }
    }
  • 相关阅读:
    ASP.net注意点小结
    AJAX笔记
    为Dreamweaver写的扩展—jQuery自动提示.
    Cisco PIX防火墙配置上
    Cisco PIX防火墙配置下
    基于DNS的负载均衡
    c#使用文本框TextBox使用ctr+enter直接跳到指定Button
    Google marker
    C#中的关键字详解
    android中,锁屏之后是不是会关掉部分服务?怎么让我的服务不被关掉?
  • 原文地址:https://www.cnblogs.com/Saurus/p/6222441.html
Copyright © 2011-2022 走看看