A
题目大意
有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
题目大意
给定一个数字序列和一个数字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;
}
}