传送门
大意:
有价值分别为1..6的大理石各a[1..6]块,现要将它们分成两部分,使得两部分价值之和相等,问是否可以实现。其中大理石的总数不超过20000。
解题思路:
妥妥的多重背包+二进制拆分,主要写一下二进制拆分存个档(儿时的噩梦)。
总所周知,20,21,22,……2k-1从中挑选若干个相加可以得到0~2k-1中的任意数。那么将一个数s进行二进制拆分,首先要做的就是找到最大k满足2k-1<=s,设c=s-2k+1。显而易见20,21,……,2k-1,c可以从中挑选若干个数相加得到0~s中的任意数。这题要做优化就是从这个思路中来,拿价值为1的大理石举例,设有t1个价值为1的大理石,可以将t1拆分为20,21,22,……,2k-1,c,然后就可以将多重背包化为01背包去解决,每个数s可以化解出log(s)个,总复杂度o(nlogn)
#include<bits/stdc++.h> using namespace std; int num[7][10086]; bool bk[100086]; int main() { int t[10]; while(1){ int sum=0; for(int i=1;i<=6;i++){ scanf("%d",&t[i]); sum+=t[i]*i; } if(sum==0) break; if(sum&1){ cout<<"Can‘t"<<endl;continue; } sum/=2;for(int i=1;i<=sum;i++) bk[i]=false;bk[0]=true; for(int i=1;i<=6;i++){ int t1=0,t2=0; while(t[i]>=(1<<t1)){ num[i][t1]=(1<<t1);t1++; } if(t[i]-(1<<t1)) num[i][t1++]=t[i]-(1<<t1); for(int j=0;j<t1;j++){ for(int h=sum;h>=i*num[i][j];h--){ bk[h]|=bk[h-i*num[i][j]]; } } } if(bk[sum]) cout<<"Can"<<endl; else cout<<"Can‘t"<<endl; } }
原文地址:https://www.cnblogs.com/r138155/p/12663900.html
时间: 2024-10-11 04:04:08