刁钻的顾客
发布时间: 2017年7月3日 10:23 时间限制: 3000ms 内存限制: 128M
XJTU校园内新开一家商店,可是来了一位刁钻的顾客要购买商品A和商品B。关于商品的质量,共有n个评分,每个评分即一个整数来表示该产品在某一方面的质量。商品A的评分表示为a1~an,商品B表示为b1~bn。
令店老板为难的是,这个刁钻的顾客要求商品A的总评分比商品B的总评分多2的正整数幂,这样他才会购买。好在店老板可以任意定义每个评分的重要性,也就是赋予这个评分一个权值(所有商品采用同一套权值)。重要性只有三档:不重要、一般和重要,它们的权值分别是1,3,5。商品的总评分就是它们在n个方面的评分乘以相应权重之和。店老板能否找到一组权重,使得商品A的总评分比商品B的总评分多2的正整数幂?
对于第一组样例,权重{1,5}是一个可行解,此时A总分为22,B总分为6,22-6=16。
多组数据。
第一行是一个整数n,商品评分的数量。
第二行是n个整数a1~an,表示商品A的评分。
第三行是n个整数b1~bn,表示商品B的评分。
其中:
2<=n<=20
1<=ai,bi<=10000000
如果可以找到一组满足要求的权重,输出“Yes”,否则输出“No”,不包括引号。
2 2 4 1 1 2 3 2 3 1
Yes No
对于这道题目,直接暴力枚举,时间复杂度是O(3^(20))是会爆掉的,而如果我们采用折半枚举地方法,时间复杂度只有O(3^20 * LOG(3^20))
详细解释bai's白书上有例子。直接附AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
LL a[22],b[22],mi[33];
LL sa[int(1e7)];
LL sb[int(1e7)];
int cnta;
int cntb;
int n;
LL pow(LL x,LL p){LL ans = 1;while(p){if(p & 1){ans *= x;}x *= x;p >>= 1;}return ans;
}
void sp(LL arr[],int& cnt,int l,int r){int n = r - l + 1;for(int S = 0;S < pow(3,n);S++){int tmpS = S;int ans = 0;for(int i = 0;i < n;i++){int w = tmpS%3;ans += (2*w+1)*(a[i + l] - b[i + l]);tmpS /= 3;}arr[cnt++] = ans;}
}
int main(){mi[0] = 1;for(int i = 1;i <= 30;i++){mi[i] = mi[i-1] * 2;}while(~scanf("%d",&n)){cnta = cntb = 0;for(int i = 0;i < n;i++){scanf("%lld",&a[i]);}for(int i = 0;i < n;i++){scanf("%lld",&b[i]);}sp(sa,cnta,0,n/2);sp(sb,cntb,n/2+1,n-1);sort(sb,sb + cntb);for(int i = 0 ;i < cnta;i++){for(int t = 1;t <= 30;t++){LL t_mi = mi[t];int f = 0;if((sa[i] == t_mi && cntb == 0 )|| *lower_bound(sb,sb+cntb,t_mi - sa[i]) == t_mi - sa[i]){f = 1;}if(f){puts("Yes");goto end;}}}puts("No");end:;}return 0;
}