Codeforces Round #638 (Div. 2)

地址:http://codeforces.com/contest/1348

 

     题意:2^1,2^2....2^n,分成两部分,使两部分的差最小。

     解析:可以发现,n越大,2^n越大,和前面的差距越来越大。所以第一部分先把2^n先加入,再陆续加入2^1,2^2.....直到n/2个即可。

#include<iostream>
#include<cstdio>
#include<cmath>
typedef long long ll;
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll n;
        cin>>n;
        ll sum=0;
        for(int i=1;i<=n;i++)
            sum+=pow(2,i);
        ll sum2=pow(2,n);
        int ans=1;
    //    cout<<sum<<endl;
        for(int i=1;i<=n;i++)
        {
            if(ans==n/2)
                break;
            sum2+=pow(2,i);
        //    cout<<sum2<<endl;
            ans++;
        }
        cout<<fabs(sum-sum2-sum2)<<endl;
    }
}

 

     题意:给出n个数和k,把所给数组变成每k个的和都相等。操作是添加任意的1-n之间的数字到任意位置。输出任意答案,否则输出-1

     解析:可以推出,当所给数组的种类数>k时,是肯定构造不出的,所以直接输出-1。那么种类数ans<=k时,如果ans==k,那么可以把每个数都扩成k个数,包含所有种类且不重复,这样就满足了每k个数和相等而且符合原数组的顺序。ans<k时,操作一样,只是不够K个的部分用同一个数字填充就可以了。对题中给的最后一个样例,我们可以输出这个:n*k=16,2  3  4  1  2 3  4  1  2 3  4  1 2 3  4  1

 

#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
typedef long long ll;
using namespace std;
const int maxn=1e4+10;
int a[maxn];
int b[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n , k ;
        cin>>n>>k;
        map<int,int>mp;
        for(int i =1;i<=n;i++)
        {
            cin>>a[i];
            mp[a[i]]++;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(mp[i]!=0)
                ans++;
        }
        if(ans>k)
        {
            cout<<"-1"<<endl;
        }
        else
        {
            int tot=1;
            for(int i=1;i<=n;i++)
            {
                if(mp[i]!=0)
                    b[tot++]=i;
            }
            if(ans<k)
            {
                for(int i=ans+1;i<=k;i++)
                    b[tot++]=1;
            }
//            for(int i=1;i<tot;i++)
//                cout<<b[i]<<"  ";
//                cout<<endl;
            cout<<n*k<<endl;
            for(int i = 1; i <= n ; i++)
            {
                for(int j=1;j<tot;j++)
                    cout<<b[j]<<" ";
            }
            cout<<endl;
        }
    }
}

 

 

     题意:初始只有1个细胞,权值为1,可以在白天选择分裂和不分裂,晚上权值会+1。问权值和达到n,最少需要几天,并输出每天多少细胞要分裂。

     解析:很明显,分裂后再全体+1肯定比不分裂权值+1增加的多,所以对于全分裂,这里是权值最大值,全体不分裂,是权值最小值,所以可以得出每一天的权值区间:

        [2,1+2]    [3,1+2+4]   [4,1+2+4+8]。

        因为问最少需要多少天,肯定是让他们尽量分裂。所以只看最大权值的变化,是:2^0+2^1+2^2.....得出这个sum值,如果sum==n,那么正好,否则把n-sum加入到vector中,再排个序,v[i]-v[i-1]就是每天需要分裂的细胞数了(这个可以手动推出的)。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll n ;
        cin>>n;
        vector<ll>v;
        for(int i=1;i<=n;i<<=1)
        {
            v.push_back(i);
            n=n-i;
        }
        if(n)
            v.push_back(n);
        sort(v.begin(),v.end());
        cout<<v.size()-1<<endl;
        for(int i=1;i<v.size();i++)
            cout<<v[i]-v[i-1]<<" ";
        cout<<endl;
    }
}

 

posted @ 2020-05-03 20:13  liyexin  阅读(153)  评论(0编辑  收藏  举报