「Codeforces」Phoenix #638 div2

A

A. Phoenix and Balance
在这里插入图片描述

题目大意

有n个硬币,每个的价值为21,22,23,… 2n,n为偶数。现在要求把这n个硬币分为两堆,使得两堆的价值差距最小。

题目解析

看到2的n次方首先要想到二进制,n个硬币的价值可以用二进制这样来表示:
在这里插入图片描述
假设n个硬币价值总和为sum

我们想要分到最平衡的两堆的话,就要使一堆尽可能的逼近sum/2:
在这里插入图片描述
我们知道,任何一堆的价值和sum/2的差值相同,所以我们可以只关注其中的一堆。求出之后差值*2即可。
于是我们现在关注价值较小的那一堆:
我们发现,如果选中某个物品,只需要在其价值对应的二进制位上标记1即可。现在这转化成了一个数学问题,给定n/2个1,填充到如图的方格中,使形成的二进制数字最大
在这里插入图片描述
很显然,把1从高位到低位排才是最大的。在这里插入图片描述
在这里插入图片描述
两者相减得:

在这里插入图片描述
即sum/2-value(smallpile)=2n/2-1
再将结果乘以2即可
结果为2n/2+1-2

代码输出直接使用math.h头文件中pow()函数即可

#include <iostream>
#include <cmath>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        cout<<pow(2,n/2+1)-2<<endl;
    }
	return 0;
}

B

B. Phoenix and Beauty
在这里插入图片描述
在这里插入图片描述

题目大意

给定一个数字序列和一个数字k,问是否能通过在任意位置增加任意多元素的方式使得序列中任意k个连续数字之和都相同。

题目解析

由任意k个数字的和都相同,我们想到如果序列中都是周期为k的子串很显然可以符合这种特性。那么我们的目的就是构造一个由周期串组成的序列。
由于序列中的每一个数字都是周期为k的串的元素之一。所以序列中数字的种数一定要小于等于k。

对数字种类进行分析:
数字种类>k:肯定构建不了,返回-1
数字种类<=k:肯定可以构建

为什么种类<=k就肯定可以构建呢?
我们在这里可以提出这样一种构造方法:
将周期子串设为不同种类的数字,子串至少每个数字都有一个。
例如:数字一共有 1 ,3,4,5,6。 5种
k=7
那么我们可以构建子串为1 3 4 5 6 1 3
对于给定序列的每一个数字,我们都用这个子串替换,那么这个序列就是由周期子串组成的。

至于一个数字怎么用一个子串替换,在其之前加上子串中该数字之前的所有数字,在其之后加上子串中该数字之后所有数字。

代码:

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
int vis[110]={0};
int a[110];
vector<int> b;
int main(){
    int t;
    cin>>t;

    while(t--){
        int ty=0;b.clear();
        memset(vis,0, sizeof(vis));
        int n,k,maxx=0;
        cin>>n>>k;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            if(vis[a[i]]==0) {ty++;b.push_back(a[i]);}
             vis[a[i]]++;
            if(maxx<vis[a[i]]) maxx=vis[a[i]];
        }
        if(ty>k) {
            cout<<-1<<endl;
            continue;
        }
        if(k==n||k==1){
            cout<<n<<endl;
            for(int i=1;i<=n;i++) cout<<a[i]<<' ';
            cout<<endl;
            continue;
        }
        while(b.size()<k) b.push_back(b.front());
        cout<<k*n<<endl;
        for(int i=1;i<=n;i++)
            for(int j:b){
                cout<<j<<' ';
            }

        cout<<endl;


    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值