您的位置:首页 > 其它

2017西安交大ACM小学期 刁钻的顾客[3进制+折半枚举]

2017-07-10 16:49 246 查看


刁钻的顾客

发布时间: 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”,不包括引号。

样例输入1 复制
2
2 4
1 1
2
3 2
3 1


样例输出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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息