题目大意 : 有N个硬币(N<=18),问能否在每个硬币使用不超过两次的情况下支付正好K的面额。
思路 : dfs构造出用这些硬币用前一半能支付的所有费用和后一半能支付的所有费用。之后排序,枚举前一半的每个面值在第二个里面二分寻找即可。(或者用set保存)。
想到一半一半处理然后综合,其实这个题跟1127很类似。以至于我刚开始一直想着怎么用状态压缩去求所有的情况。这里每个硬币可以用一次、两次、零次。而那个题是可以用一次或者零次。所以这个题就不能用01表示了。所以也就不能用状态压缩了。
没有办法,只有搜索了。。然后枚举+二分。。
int a[maxn]; vector<int> va,vb; void pushback(int sum,int l,int r){ if(l==r){ va.pb(sum); return; } for(int i=0;i<3;i++) pushback(sum+a[l]*i,l+1,r); } void pushback2(int sum,int l,int r){ if(l==r){ vb.pb(sum); return; } for(int i=0;i<3;i++) pushback2(sum+a[l]*i,l+1,r); } int main(){ int T; scanf("%d",&T); for(int tt=1;tt<=T;tt++){ va.clear(); vb.clear(); int n,k; scanf("%d%d",&n,&k); int ta=n>>1; int tb=n-ta; for(int i=0;i<n;i++) scanf("%d",&a[i]); pushback(0,0,ta); pushback2(0,ta,n); sort(va.begin(),va.end()); sort(vb.begin(),vb.end()); bool can=false; for(size_t i=0;i<vb.size();i++){ if(*lower_bound(va.begin(),va.end(),k-vb[i])==k-vb[i]){ can=true; break; } } printf("Case %d: ",tt); if(can)puts("Yes"); else puts("No"); } return 0; }