题目描述
作为彩虹岛上最擅长打铁的人,??????今天一共打了??块大小为1的铁。为了保存这些铁块,他打算制作若干个箱子。其中,第1个箱子的容量为1(可装1块铁),之后每个箱子的容量都是它前一个箱子的容量的2倍。
但是他只会打铁,并不擅长制作箱子。制作完成后,他发现第1个箱子的容量是2(而不是1),之后每个箱子的容量都比它前一个箱子的容量的2倍少1,即第2个箱子的容量是3 = 2 × 2 − 1,第3个箱子的容量是5 = 3 × 2 − 1,第4个箱子的容量是9 = 5 × 2 − 1,依此类推。
作为一个勤俭节约的人,??????想知道能否把这??块铁全部放入箱子中并使得所有装有铁块的箱子都装满了且没有空余。
输入描述:
输入第一行为一个整数??(1 ≤ ?? ≤ 100),表示一共有??组数据。
对于每组测试数据:
第一行为一个整数??(1 ≤ ?? ≤ 109),表示??????一共打了??块铁。
输出描述:
对于每组测试数据,如果能够按照要求放进箱子里面则输出“YES”,否则输出“NO”。
示例1
输入
2 1 8
输出
NO YES
说明
对于第一组样例,无法按照要求放入箱子中。
对于第二组样例,用容量为3和容量为5的箱子恰好能够放下8块铁。
【分析】:每个背包的大小是个方程式f(n)=2^(n-1)+1 ,所以每个生成数是一个数加上其二进制上1的数目 。我们枚举1的数目i,最多不超过25,减去其并计算减去后的数的二进制1的数目n,如果n等于i就成功了。有2^(n-1)这个东西,它组成的数系能覆盖整个整数系, 但加了个1 。可知二进制中有几个1就加几个1。
【代码】:
二进制
折半枚举
#include <bits/stdc++.h> using namespace std; int main(){ int T,min;cin>>T; while(T--) { int x,i; cin>>x; if(x>31) min=31; else min=x; for(i=1;i<=min;i++) if(__builtin_popcount(x-i)==i) {cout<<"YES";break;} if(i>min) cout<<"NO"; cout<<‘\n‘; } return 0; }
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define INFLL 0x3f3f3f3f3f3f3f3f #define x first #define y second #define LL long long using namespace std; const int maxn = 2e5+5; int T; int n; LL a[35]; LL num1[2<<16]; LL num2[2<<16]; int p1 = 0; int p2 = 0; void dfs1(int l,int r,LL sum,int deep) { if(deep==r+1){ num1[p1++] = sum; return ; } dfs1(l,r,sum,deep+1); dfs1(l,r,sum+a[deep],deep+1); } void dfs2(int l,int r,LL sum,int deep) { if(deep==r+1){ num2[p2++] = sum; return ; } dfs2(l,r,sum,deep+1); dfs2(l,r,sum+a[deep],deep+1); } void init() { a[0] = 2; for(int i = 1;i<31;i++){ a[i] = a[i-1]*2-1; } dfs1(0,31/2,0,0); dfs2(31/2+1,30,0,31/2+1); sort(num1,num1+p1); sort(num2,num2+p2); } int main() { init(); scanf("%d",&T); while(T--){ scanf("%d",&n); int falg = 0; for(int i = 0;i<p1;i++){ if(num1[i]>n) break; int p = lower_bound(num2,num2+p2,n-num1[i])-num2; // cout<<num1[i]<<‘ ‘<<p<<‘ ‘<<num2[p]<<endl; if(p<p2&&num2[p]+num1[i]==n){ falg = 1; break; } } if(falg){ puts("YES"); } else{ puts("NO"); } } }