zoukankan      html  css  js  c++  java
  • TJUOJ4168解题报告【覆盖集合,想法题】

    题目地址:

      http://acm.tju.edu.cn/toj/showp4168.html

    题目概述:

      给出一个集合以及一个m,集合中一开始有n个数,要求加入最少的数使得这个集合的各个子集的和能够覆盖1~m。

      例如集合A={1,3},m=6,这时只需要将2加入A中,A的所有子集为[1], [2], [3], [1,2], [1,3], [2,3], [1,2,3],他们的和分别是1,2,3,3,4,5,6,能够覆盖1~6这个区间,所以答案为1。

    大致思路:

      一开始想到二进制位上去了,觉得每个数的二进制位都有个贡献之类的,结果还是too naive啊,跟正解差的太多。

      首先对子集A的元素排个序,然后假设当前子集中最大的数为a[i-1],能够覆盖的范围是1~mx,那么如果a[i]>mx+1的话,必须要插入mx+1这个数才能使覆盖的范围仍旧连续,而插入mx+1,会使得覆盖的范围变成2*mx+1,此时再比较a[i]与当前的mx的大小,直到a[i]<=mx+1时加入a[i]会使得覆盖的范围变成mx+a[i],一直这么考虑下去就ok。

    复杂度分析:

      首先对于数m来说,最多只需要log2(m)个数就可以满足题意了,那么插入的复杂度应该就是O(n+logm),之前还需要排序,就是O(nlogn),总的的复杂度即O(nlogn)了。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <ctime>
    #include <map>
    #include <assert.h>
    #include <stack>
    #include <set>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    #define sacnf scanf
    #define scnaf scanf
    #define maxn 100010
    #define maxm 20010
    #define inf 1061109567
    #define INF 0x3f3f3f3f
    #define Eps 0.000001
    const double PI=acos(-1.0);
    #define mod 1000000007
    #define MAXNUM 10000
    #define For(i,j,k) for(int (i)=(j);(i)<=(k);(i)++)
    #define mes(a,b) memset((a),(b),sizeof(a))
    typedef long long ll;
    typedef unsigned long long ulld;
    void Swap(int &a,int &b) {int t=a;a=b;b=t;}
    ll Abs(ll x) {return (x<0)?-x:x;}
    
    int a[maxn];
    
    int main()
    {
        //freopen("data.in","r",stdin);
        //freopen("data.out","w",stdout);
        //clock_t st=clock();
        int T;scanf("%d",&T);
        while(T--)
        {
            int n;ll m;scanf("%d%lld",&n,&m);
            For(i,1,n) scanf("%d",&a[i]);
            sort(a+1,a+1+n);ll ms=0;int cnt=0;
            for(int i=1;i<=n;i++)
            {
                if(ms>=m) break;
                while(a[i]>ms+1&&ms<m) cnt++,ms=ms*2+1;
                ms=ms+a[i];
            }
            while(ms<m) cnt++,ms=ms*2+1;
            printf("%d
    ",cnt);
        }
        //clock_t ed=clock();
        //printf("
    
    Time Used : %.5lf Ms.
    ",(double)(ed-st)/CLOCKS_PER_SEC);
        return 0;
    }
  • 相关阅读:
    [LeetCode] 26 Remove Duplicates from Sorted Array
    归并排序
    插入排序
    选择排序
    冒泡排序
    单链表排序
    如何实现单链表反转
    Linux基础——centos 跳过管理员密码进行登录(单用户模式、救援模式)
    response.sendRedirect()与request.getRequestDispatcher().forward()区别
    json-lib——JsonConfig详细使用说明
  • 原文地址:https://www.cnblogs.com/CtrlKismet/p/7157439.html
Copyright © 2011-2022 走看看