Codeforces Round #638 (Div. 2)
CF1348A
A - Phoenix and Balance
给一个数n即你有2、4、8、16…2^n这些数,把他分成两堆保证和的差值最
很容易知道前n-1项和小于第n项,2^n-2 和2的n次方,所以把最后一项和前面几项相加使得和靠近总和的一半就行
#include
#include
using namespace std;
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
long long sum=0;
long long ans=1<<n;
sum=ans+(1<<(n/2))-2;
printf("%lld\n",sum-((1<<(n+1))-2-sum));
}
return 0;
}
CF1348B
B - Phoenix and Beauty
插入1-n中的数使得任何连续的k个数和相等
先检查n个数中有多少个不同的数,如果超过k那么直接输出-1不可能实现,自己可以想想看,如果小于k那就从1-n中选几个数使得可选数的个数等于k,然后顺序可以随便了打印n次可选数序列总个数当然就是n*k了,等于k的话就免去了从1-n中选可选数的步骤,代码比较冗余,当时没想着怎么缩短
#include
#include
#include
#include
using namespace std;
int a[105];
int vis[105];
int main() {
int t;
scanf("%d",&t);
while(t--) {
int n,k;
scanf("%d%d",&n,&k);
memset(vis,0,sizeof(vis));
vector<int>v;
for (int i=0; i<n; i++) scanf("%d",a+i);
if (n==k) {
printf("%d\n",n);
printf("%d",a[0]);
for (int i=1; i<n; i++) printf(" %d",a[i]);
printf("\n");
} else {
int num=0;
for (int i=0; i<n; i++) {
if (vis[a[i]]==0) {
v.push_back(a[i]);
num++;
}
vis[a[i]]++;
}
if (num>k) printf("-1\n");
else {
printf("%d\n",k*n);
if (num<k) {
for (int i=1; i<=n; i++) {
if (vis[i]==0&&num<k) v.push_back(i),num++;
}
}
int flag=0;
int nflag=0;
while(flag<n) {
flag++;
for (int j=0; j<v.size(); j++) {
if (nflag) printf(" ");
nflag=1;
printf("%d",v[j]);
}
}
printf("\n");
}
}
}
return 0;
}
CF1348C
C - Phoenix and Distribution
看出现的最小的字母有多少个,如果小于k就可以顺延按照这段序列排序的第k个字符,因为剩下的字符都可以放在最小的那个字符后面,如果等于k就看这段序列中一共出现过几个不同的字符来分别处理
#include
#include
#include
using namespace std;
int num[30];
int main() {
int t;
scanf("%d",&t);
while(t--) {
int n,k;
scanf("%d%d",&n,&k);
string s;
cin>>s;
int i=0;
memset(num,0,sizeof(num));
while(s[i]) {
num[s[i]-'a']++;
i++;
}
int pos;
for (int j=0; j<26; j++) {
if (num[j]!=0) {
pos=j;
break;
}
}
if (num[pos]<k) {
int ans=num[pos];
for (int j=pos+1; j<26; j++) {
if (num[j]!=0){
ans+=num[j];
if (ans>=k){
printf("%c\n",j+'a');
break;
}
}
}
} else {
int ans=0;
for (int j=0; j<26; j++) if (num[j]!=0) ans++;
if (ans==1) {
int num1=num[pos];
if (num1%k) num1=num1/k+1;
else num1=num1/k;
while(num1--) {
printf("%c",pos+'a');
}
printf("\n");
} else if (ans==2) {
if (num[pos]==k) {
printf("%c",pos+'a');
for (int j=pos+1; j<26; j++) {
if (num[j]!=0) {
pos=j;
break;
}
}
int num1=num[pos];
if (num1%k) num1=num1/k+1;
else num1=num1/k;
while(num1--) {
printf("%c",pos+'a');
}
printf("\n");
} else {
printf("%c",pos+'a');
num[pos]-=k;
for(int j=pos; j<26; j++) {
while(num[j]--) {
printf("%c",j+'a');
}
}
printf("\n");
}
} else {
printf("%c",pos+'a');
num[pos]-=k;
for(int j=pos; j<26; j++) {
while(num[j]--) {
printf("%c",j+'a');
}
}
printf("\n");
}
}
}
return 0;
}
CF1348D
D - Phoenix and Science
每天白天你可以选择已有的x个细胞中y个细胞分裂y>=0&&y<=x每天晚上每个细胞会增加1的重量,求最快到达n的重量的方法
总之就是贪心的策略,只不过要考虑最后两天的处理
#include
#include
#include
using namespace std;
int main(){
int t;
scanf("%d",&t);
while(t--){
long long n;
scanf("%lld",&n);
if (n==2) printf("1\n0\n");
else{
vector<long long>v;
int nflag=0;
long long num=2;
long long num1=1;
int ans=0;
long long sum=1;
while(sum<n){
if (sum+num1*2<=n){
v.push_back(num1);
num1=num1*2;
sum=sum+num1;
}
else{
if (sum+num1>n){
num1=num1*2;
sum=sum+num1;
num1=num1/2;
long long sub=sum-n;
sum=sum-num1*2;
if (sub%3){
if (sub/3+1<=v[v.size()-1]){
long long num2=num1/2;
num1=num1/2-sub/3;
v[v.size()-1]=num1;
v.push_back(num1+num2-sub%3);
sum=n;
}
else{
long long num2=v[v.size()-1];
sum=sum-num2*2;
long long num4=sum+num2+num2*2-n;
v[v.size()-1]=0;
v.push_back(num2-num4);
sum=n;
}
}
else{
if (sub/3<=v[v.size()-1]){
long long num2=v[v.size()-1];
num1=v[v.size()-1]-sub/3;
v[v.size()-1]=num1;
v.push_back(num1+num2);
sum=n;
}
else{
long long num2=num1/2;
sum=sum-num2*2;
long long num4=sum+num2+num2*2-n;
v[v.size()-1]=0;
v.push_back(num2-num4);
sum=n;
}
}
}
else{
v.push_back(n-sum-num1);
num1=n-sum;
sum=n;
}
}
}
printf("%d\n",v.size());
int flag=0;
for (int i=0;i<v.size();i++){
if (flag) printf(" ");
flag=1;
printf("%lld",v[i]);
}
printf("\n");
}
}
return 0;
}