[NOIP2017模拟]Ball

来源:互联网 发布:拉比 婴儿床 知乎 编辑:程序博客网 时间:2024/05/17 01:51

题目背景
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。

分析:如果说连乘的话肯定超long long,有没有办法把它变小,最好把它变成加法呢?有,用对数!这样只需要把读入的数取对数再加起来,连int都不会超!!!但是,要注意判负数和0。
还有一种算法,就是取一个极大值为基数,连乘到大于它就又新开一个数组重新开始乘,最后比较哪个开的数组多哪个就更大(当然要判负数和0),如果一样那就一一对应相除得到一堆分数再相乘,最后得到的数小于1就是Alice赢,反之Bob赢。

代码
解法一

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>#include<set>using namespace std;int getint(){    int sum=0,f=1;    char ch;    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());    if(ch=='-')    {        f=-1;        ch=getchar();    }    for(;isdigit(ch);ch=getchar())        sum=(sum<<3)+(sum<<1)+ch-48;    return sum*f;}const int maxn=100010;int T,n,m,bj10,bj1,bj20,bj2;//bj1、bj2判断正负,bj10、bj20判断是否有0int a1,a2;double ans1,ans2;int main(){    freopen("ball.in","r",stdin);    freopen("ball.out","w",stdout);    T=getint();    while(T--)    {        bj1=bj2=bj10=bj20=0;        ans1=0,ans2=0;        n=getint();        for(int i=1;i<=n;++i)        {            a1=getint();            if(a1<0)            {                bj1^=1;                ans1+=log10(-a1);//log(这个是e为底)、log2、log10都是C++自带的函数            }            else if(a1==0)            {                bj10=1;                continue;//千万不要学我在这里自信满满地break掉,数据都还没读完啊......            }            else                ans1+=log10(a1);        }        m=getint();        for(int i=1;i<=m;++i)        {            a2=getint();            if(a2<0)            {                bj2^=1;                ans2+=log10(-a2);            }            else if(a2==0)            {                bj20=1;                continue;            }            else                ans2+=log10(a2);        }        if(bj10!=1&&bj20!=1)//两个都不为0        {            if((bj1==1&&bj2==0)||(bj1==1&&bj2==1&&ans1>ans2)||(bj1==0&&bj2==0&&ans1<ans2))//Alice负Bob正、Alice负得更厉害、Bob正得更厉害都是Alice赢                cout<<"Alice"<<'\n';            else if((bj1==0&&bj2==1)||(bj1==1&&bj2==1&&ans1<ans2)||(bj1==0&&bj2==0&&ans1>ans2))                cout<<"Bob"<<'\n';        }        else if(bj10==1)        {            if(bj2==1)                cout<<"Bob"<<'\n';            else                cout<<"Alice"<<'\n';        }        else if(bj20==1)        {            if(bj1==1)                cout<<"Alice"<<'\n';            else                cout<<"Bob"<<'\n';        }    }    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;        }        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)        {            if(check1==1&&check2==0) {printf("Alice\n");continue;}            if(check1==0&&check2==1) {printf("Bob\n");continue;}        }        if(flag1==true&&flag2==false)        {            if(check2==1) {printf("Bob\n");continue;}            else {printf("Alice\n");continue;}        }        if(flag1==false&&flag2==true)        {            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;}            long long x=sum2[46];        }        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;}

本题结。