CF806C:Prairie Partition(二分)

C. Prairie Partition
time limit per test 2 seconds
memory limit per test 256 megabytes
input standard input
output standard output
It can be shown that any positive integer x can be uniquely represented as x = 1 + 2 + 4 + ... + 2k - 1 + r, where k and r are integers, k ≥ 0, 0 < r ≤ 2k. Let's call that representation prairie partition of x.

For example, the prairie partitions of 12, 17, 7 and 1 are:

12 = 1 + 2 + 4 + 5,
17 = 1 + 2 + 4 + 8 + 2,

7 = 1 + 2 + 4,

1 = 1.

Alice took a sequence of positive integers (possibly with repeating elements), replaced every element with the sequence of summands in its prairie partition, arranged the resulting numbers in non-decreasing order and gave them to Borys. Now Borys wonders how many elements Alice's original sequence could contain. Find all possible options!

Input
The first line contains a single integer n (1 ≤ n ≤ 105) — the number of numbers given from Alice to Borys.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 1012; a1 ≤ a2 ≤ ... ≤ an) — the numbers given from Alice to Borys.

Output
Output, in increasing order, all possible values of m such that there exists a sequence of positive integers of length m such that if you replace every element with the summands in its prairie partition and arrange the resulting numbers in non-decreasing order, you will get the sequence given in the input.

If there are no such values of m, output a single integer -1.

Examples
input
8
1 1 2 2 3 4 5 8
output

input
6
1 1 1 2 2 2
output
2 3 
input
5
1 2 4 4 4
output
-1
Note
In the first example, Alice could get the input sequence from [6, 20] as the original sequence.

In the second example, Alice's original sequence could be either [4, 5] or [3, 3, 3].


题意:给出一个序列,问这个序列可以由多少个数分解而来,分解方式如题。
思路:分解数ans的上限为1的数目,加如可以分解为x组,其中x<count[1],那么[x,count[1]]的都可以作为答案,因为将1提取出来又是新的一组。那么可以二分出可分解的最小组数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
int n;
long long fac[55];
int cnt[55];
int need1[55];
vector<long long> e;

bool check(int x)
{
    int have[55];
    int need[55];

    int minn=x;
    have[51]=0;
    for(int i=0;i<=50;i++)
    {
        have[i]=need[i]=0;
        minn=min(minn,cnt[i]);
        have[i]=minn;
        int id=i;
        if(id>0)
            id--;
        need[id]+=(cnt[i]-have[i]);
    }

    for(int i=0;i<=50;i++)
    {
        have[i]=have[i]-have[i+1];
    }

    int res=0;
    for(int i=0;i<=50;i++)
    {
        res+=(need[i]+need1[i]);
        int tp=min(res,have[i]);
        res-=tp;
        have[i]-=tp;
    }
    if(res==0)
        return true;
    else
        return false;
}
int bin(int t)
{
    int l=1,r=t;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(check(mid))
        {
            r=mid;
        }
        else
        {
            l=mid+1;
        }
    }
    if(check(r))
        return r;
    else
        return t+1;
}
int main()
{
    fac[0]=1;
    for(int i=1;i<=50;i++)
    {
        fac[i]=fac[i-1]*2;
    }
    while(~scanf("%d",&n))
    {
        for(int i=0;i<=50;i++)
            cnt[i]=0,need1[i]=0;
        e.clear();

        for(int i=0;i<n;i++)
        {
            long long tp;
            scanf("%lld",&tp);
            int f=0;
            for(int j=0;j<=50;j++)
            {
                if(fac[j]==tp)
                {
                    cnt[j]++;
                    f=1;
                    break;
                }
            }
            if(f==0)
                e.push_back(tp);
        }

        for(int i=0;i<e.size();i++)
        {
            int id=log2(e[i]);
            if(fac[id]==e[i])
                id--;
            need1[id]++;
            //cout<<id<<endl;
        }

        int ans=bin(cnt[0]);
        if(ans>cnt[0])
            printf("-1\n");
        else
        {
            for(int i=ans;i<=cnt[0];i++)
                printf("%d ",i);
            printf("\n");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/c_czl/article/details/84675192