题意:n个物品,每个物品重量1/2^k[i],问可不可以分成两份,让这两份的总量都大于1/2
题解:因为两份都要大于1/2,那么我们两份都找出1/2,剩下的就无所谓了。我们把问题转化为,两份都需要找到一个1,因为 1/2==1/4+1/4,所以一个1等价于两个2,4个3.....,我们先从小到大排个序,令cnt1,cnt2表示这两组当前还需要pre这样的数的数量,如果cnt1+cnt2>后面剩余的数就直接break即可,cnt1和cnt2都为0时,即两组都已达到1/2,即符合条件
#include<bits/stdc++.h>
using namespace std;
int vis[100010];
struct node{
int id;
int x;
}a[100010];
int n;
int cmp(const node &xx,const node &yy)
{
return xx.x<yy.x;
}
int main()
{
int T;
scanf("%d",&T);
int nn=1;
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i;
vis[i]=0;
}
printf("Case %d: ",nn++);
sort(a+1,a+1+n,cmp);
int flag=1;
int pre=1; // pre初始为1,两组各需要一个即可
int cnt1=1,cnt2=1;
for(int i=1;i<=n;i++)
{
while(cnt1+cnt2<=n-i+1&&pre<a[i].x) // 转化为当前这个数,更新需要的数的数量
{
cnt1=cnt1*2;
cnt2=cnt2*2;
pre++;
}
if(cnt1+cnt2>n-i+1) // 剩余的数的数量无法满足
{
flag=0;
break;
}
if(cnt1)
{
cnt1--;
vis[a[i].id]=1;
}
else
{
cnt2--;
}
if(!cnt1 && !cnt2) break; // 两个都满足了
}
if(flag==0 || cnt1 || cnt2) puts("NO");
else
{
puts("YES");
for(int i=1;i<=n;i++)
{
printf("%d",vis[i]);
}
printf("\n");
}
}
return 0;
}