Justice
解法:首先,对于大于等于100000的ki值,我们不需要管,如果这些数总和大于等于1,那么肯定有解,我们先判断这些数总和是否大于等于1,我们用数组vis统计每个数出现次数,然后从大到小枚举x,vis[x] += vis[x + 1] / 2,如果到了最后vis[0]不为0,那么满足条件,第二步我们来组合,我们取出所有值小于等于20的ki,把他们全部变成2^(20 - ki),然后从到达小枚举这些数,直到这些数相加等于2^(19)为止,然后把这些数标记为1,其他全部标为0即可。
---------------------
作者:一只叫橘子的猫
来源:CSDN
原文:https://blog.csdn.net/ccsu_cat/article/details/96307362
版权声明:本文为博主原创文章,转载请附上博文链接!
!!!
1e5 / (2^21)是小于<1/2 所以 当总和大于1时,在1~20之间的数之和一定大于1/2 则只需要在(1~20)的数中找数并凑成1/2;
而且一定能 凑整 1/2 既然能大于等于1 则至少有可以凑成1/2或现存1/2;
排序后从小到大凑
#include<bits/stdc++.h> using namespace std; int a[100005],anss[100005],b[100005],ksm[21]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576}; struct node{ int v,id; }aa[100005]; bool cmp(node a,node b) { return a.v<b.v; } int main() { int t; cin>>t; for(int j=1;j<=t;j++) { int k,sum=0,summ=0; memset(b,0,sizeof(b)); scanf("%d",&k); for(int i=0;i<k;i++) { scanf("%d",&a[i]); if(a[i]<=100000) b[a[i]]++; aa[i].v=a[i]; aa[i].id=i;//标记原来下标 } for(int i=100000;i>0;i--) { b[i-1]+=b[i]/2; } if(b[0]==0) { printf("Case %d: NO",j); } else { sort(aa,aa+k,cmp); int sum=524288; printf("Case %d: YES\n",j); for(int qq=0;qq<k;qq++) { if(aa[qq].v<=20) { if(sum-ksm[20-aa[qq].v]>=0) { sum-=ksm[20-aa[qq].v]; anss[aa[qq].id]=1; } } } for(int i=0;i<k;i++) { if(a[i]<=20) printf("%d",anss[i]); else printf("0"); anss[i]=0;//anss初始化 } } printf("\n"); } }