链接:https://ac.nowcoder.com/acm/contest/4784/H
题目描述
题意:有230 背包容量,有n个物品,每个物品体积ci=2k,求是否能恰好装满背包。
输入描述:
第一行,是一个正整数T(1 \le T \le 100000)T(1≤T≤100000),表示接下来要输入T组测试数据
接下来有T测试数据的输入,对于每组测试数据,输入格式如下:
第一行,一个整数m(1 \le m \le 100000, \sum m\le10^5)m(1≤m≤100000,∑m≤10 5)第二行,用空格隔开的m个非负整数,第i个数字是k_i (0 \le k_i < 30)k
i (0≤k i<30)
输出描述:
依次输出T行,按照输入数据的顺序依次给出每组测试数据的答案,对于一组测试数据:如果存在一种符合条件的方案,则输出一个长度为m的01串,从前往后的第i位如果是1表示原序列中第i个物品被选中装进背包,为0则表示这个物品不被选中。如果不存在符合条件的方案,请输出impossible
示例1
输入
2
4
29 1 28 28
7
0 0 1 2 3 4 15
输出
1011
impossible
思路:
我们要注意到这是二进制加法,即230== 229+229 == 229+228+228 == 228+228+228+228 ,我们可以发现二进制加法有一个特点,它不会一下子越过一个数,它是逐步上升的。例如:期望值:100(2),目标值:1000(2),不论我们以哪种加法到达1000(2),都需要经过期望值。在此题我们的期望值是230,目标值是背包物品的和,当且仅当目标值>=期望值有解。因此我们可以把物品ci按降序排列,能放的就放,若有解一定能找到背包恰好放满的解。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct node{
ll w;
int flag;
};
node a[maxn];
inline int cmp(node a,node b)
{
if(a.w==b.w)
return a.flag>b.flag;
return a.w>b.w;
}
int ans[maxn];
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
int tt;
for(int i=1;i<=n;i++)
{
cin>>tt;
a[i].w=1<<tt;
a[i].flag=i;
}
sort(a+1,a+1+n,cmp);
ll sum=1<<30;
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)
{
if(sum>=a[i].w)
{
sum-=a[i].w;
ans[a[i].flag]=1;
}
}
if(sum==0)
{
for(int i=1;i<=n;i++)
{
cout<<ans[i];
}
cout<<"\n";
}
else
cout<<"impossible"<<endl;
}
return 0;
}