题目描述:
题目背景: SOURCE:NOIP2015-SHY-9
Alice 与 Bob 在玩游戏。他们一共玩了 t 轮游戏。游戏中,他们分别获得了 n 个和 m 个小球。每个球上有一个分数。每个人的得分都为他所获得所有小球分数的乘积,分数小者获胜。问每轮游戏谁会获胜?请输出每轮游戏的胜者。数据保证不会出现平局,且两个人分数差异大于任意一个人分数的 1% 。
输入格式:
第一行为两人玩的轮数 t(1≤t≤10)。
每一轮游戏的输入中:
第一行一个整数 n,代表 Alice 获得球的个数。
第二行为 n 个整数 ai,代表 Alice 每个球的分数。
第三行一个整数 m,代表 Bob 获得球的个数。
第四行为 m 个整数 bi,代表 Bob 每个球的分数。
输出格式:
输出共 t 行,每行为该轮胜者的名字“Alice”或“Bob”。
样例输入:
1
3
2 3 4
4
1 3 4 5
样例输出:
Alice
样例说明:
Alice:2 * 3 * 4 = 24
Bob: 1 * 3 * 4 * 5 = 60
数据范围:
对于 40% 的数据:n,m,ai,bi≤10;
对于 100% 的数据:1≤n,m≤100000;-10000≤ai,bi≤10000。
题目分析:
首先明确:保证不相等且差异大于积的 1%,这样精度上就不用太担心。
此题有三种方法:
方法一:log法(标算的方法)首先我们知道
logax∗y=logax+logay
。这样对于连乘就可以转化为分别取对数后相加,两者的大小关系是不变的。而对于正负性和0,单独判断。正负性根据负号个数的奇偶判断。而每次取对数都是对绝对值取对数,0直接忽略掉。
PS:c++数学库里自带log,头文件加入#include<cmath>
;运用时log(x)
,底数是e。自带log还有log2(x)
和log10(x)
(底数为2,精度相对最高),没有其它底数的log了。
方法二:相除法 你可以直接一个Alice一个Bob对应相除(短的就给它补1)得到商记做double型,把商乘起来比较与1的大小关系。正负性和0要记得判断。
方法三:极大值个数法你可以设一个极大值如
1016
,直接连着乘,存入sum[tot],如果大于了
1016
,就新开一个sum[++tot]存,以此类推,最后比较一下个数,显然,个数多的大,对于个数相同的,可以利用方法二把sum对应相除比较大小。同样记得判正负性和0。
附代码:
方法一:log法
此代码中用到了pair(更简洁),不知道的请百度一下。实际上pair就是一个包含两个数据值的结构体,第一个的名字是first,第二个是second。
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;
int n,t,x;
int readint()
{
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
pair<int,double> find()//pair型的第一维处理正负号和0,第二维处理绝对值取对数的和
{
pair<int,double> result=make_pair(1,0);//两维分别赋初值1,0
n=readint();
for(int i=1;i<=n;i++)
{
x=readint();
if(x<0)
{
result.first=-result.first;
result.second+=log(-x);
}
else
{
if(x==0) result.first=0;
else result.second+=log(x);
}
}
return result;
}
int main()
{
//freopen("lx.in","r",stdin);
t=readint();
while(t--)
{
pair<int,double> x1=find();
pair<int,double> x2=find();
double ans1=x1.first*x1.second;//这样相乘就可以方便地直接比较大小了
double ans2=x2.first*x2.second;
if(ans1<ans2) printf("Alice\n");
else printf("Bob\n");
}
return 0;
}
方法二:相除法
直接copy的一位同学的
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
using namespace std;
inline int read()
{
int i=0,f=1;
char ch;
ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
i=(i<<1)+(i<<3)+ch-'0';
ch=getchar();
}
return i*f;
}
int t,n,m,a[100005],b[100005];
double c[100005];
int main()
{
t=read();
while(t--)
{
n=read();
int f1=0,f2=0;
for(int i=1;i<=n;i++)
{
a[i]=read();
if(a[i]<0)
{
f1++;
a[i]=-a[i];
}
}
m=read();
for(int i=1;i<=m;i++)
{
b[i]=read();
if(b[i]<0)
{
f2++;
b[i]=-b[i];
}
}
if(f1%2==1&&f2%2==0)
{
cout<<"Alice"<<endl;
continue;
}
if(f1%2==0&&f2%2==1)
{
cout<<"Bob"<<endl;
continue;
}
bool bz;
if(f1%2==0&&f2%2==0)bz=1;
if(f1%2==1&&f2%2==1)bz=0;
sort(a+1,a+n+1);
sort(b+1,b+n+1);
int p=0;
for(int i=1;i<=max(n,m);i++)
{
if(i>m)b[i]=1;
if(i>n)a[i]=1;
c[i]=double(a[i])/double(b[i]);
if(a[i]==0)
{
p=1;
break;
}
if(b[i]==0)
{
p=2;
break;
}
}
if(p==1)
if(f2%2==0)
{
cout<<"Alice"<<endl;
continue;
}
if(p==2)
{
if(f1%2==0)
{
cout<<"Bob"<<endl;
continue;
}
else
{
cout<<"Alice"<<endl;
continue;
}
}
sort(c+1,c+max(n,m)+1);
double ans=1;
bool bj=0;
for(int i=1;i<=max(n,m);i++)
{
ans*=c[i];
if(ans>1)
{
bj=1;
break;
}
}
if(bj)
if(!bz)cout<<"Alice"<<endl;
else cout<<"Bob"<<endl;
else
if(bz)cout<<"Alice"<<endl;
else cout<<"Bob"<<endl;
}
return 0;
}
方法三:极大值个数法
我考试时自己写的
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;
const int N=1e5+10;
const long long INF=1e16;
int check1,check2,t,n,m,check,tot1,tot2;
double sh[N],ans;
long long sum1[N],sum2[N],a[N],b[N];
bool flag1,flag2;
int readint()
{
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
int main()
{
//freopen("ball.in","r",stdin);
//freopen("ball.out","w",stdout);
t=readint();
while(t--)
{
check1=0;check2=0;check=0;tot1=1;tot2=1;flag1=false;flag2=false;
ans=1;
n=readint();
for(int i=1;i<=n;i++)
{
a[i]=readint();
if(a[i]<0)
{
check1=check1^1;//用异或判断符号个数的奇偶
a[i]=abs(a[i]);
}
if(a[i]==0) flag1=true;//flag判断是否有0
}
m=readint();
for(int i=1;i<=m;i++)
{
b[i]=readint();
if(b[i]<0)
{
check2=check2^1;
b[i]=abs(b[i]);
}
if(b[i]==0) flag2=true;
}
if(flag1==false&&flag2==false)//均不含0
{
if(check1==1&&check2==0) {printf("Alice\n");continue;}
if(check1==0&&check2==1) {printf("Bob\n");continue;}
}
if(flag1==true&&flag2==false)//Alice为0 ,Bob不为0
{
if(check2==1) {printf("Bob\n");continue;}
else {printf("Alice\n");continue;}
}
if(flag1==false&&flag2==true)//Alice不为0 ,Bob为0
{
if(check1==1) {printf("Alice\n");continue;}
else {printf("Bob\n");continue;}
}
sum1[1]=1;sum2[1]=1;
for(int i=1;i<=n;i++)
{
sum1[tot1]*=a[i];
if(sum1[tot1]>INF) {tot1++;sum1[tot1]=1;}
}
for(int i=1;i<=m;i++)
{
sum2[tot2]*=b[i];
if(sum2[tot2]>INF) {tot2++;sum2[tot2]=1;}
}
if(tot1>tot2) check=1;//比较个数
if(tot1<tot2) check=2;
if(tot1==tot2)
{
if(tot1==1)
{
if(sum1[1]<sum2[1]) check=2;
else check=1;
}
else
{
for(int i=1;i<=tot1;i++)
sh[i]=(sum1[i]*1.0)/sum2[i];//相除
for(int i=1;i<=tot1;i++)
ans*=sh[i];
if(ans<1) check=2;
else check=1;
}
}
if(check==2)
{
if(check1==0&&check2==0) {printf("Alice\n");continue;}
if(check1==1&&check2==1) {printf("Bob\n");continue;}
}
else
{
if(check1==0&&check2==0) {printf("Bob\n");continue;}
if(check1==1&&check2==1) {printf("Alice\n");continue;}
}
}
return 0;
}