codevs 2943 射箭 1--等比数列求和+高精度模板


2943 射箭 1

 
题目描述 Description

  甲乙两人去射箭,采用轮流制(甲乙甲乙……),谁先射中谁获得胜利,已知甲的命中率为,乙的命中率为,求乙获得胜利的概率。

输入描述 Input Description

  共一行,四个用空格隔开的正整数。保证

输出描述 Output Description

  共一行,一个小数,表示乙的胜率,四舍五入强制保留1000位小数

样例输入 Sample Input
1 2 7 23

样例输出 Sample Output
0.2333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333

数据范围及提示 Data Size & Hint

  对于100%的数据:



算法分析:

等比数列求和,乙第一回合赢得几率,a1=(1-a/b)*(c/d),以后的等比系数q=(1-a/b)*(1-c/d),总的通项为a1/(1-q),化简后为(c*(b-a))/(a*d-c*(b-a)),

得到的结果一定为小数,所以将分子扩大1002倍后整除,根据最后一位处理进位。

定义大整数结构,重载=,-=,+=,*=。/=,+,-,*,/等,包括高精度*单精度,高精度/单精度,高精度*高精度,高精度/高精度。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(I,start,end) for(int I=start;I<=end;I++)
#define PER(I,start,end) for(int I=start;I>=end;I--)
using namespace std;
long long tmp[2100];
struct bigNumber{//定义大整数结构 
   int len;
   long long num[2100];
   inline void operator =(long long T){//重载= 
       memset(num,0,sizeof(num));
       len=0;
       while(T){
          num[++len]=T%10;
          T/=10;
       }
   }
   inline bool operator >(const bigNumber T)const{//重载>
       if(len<T.len)return false;
       if(len>T.len)return true;
       PER(ii,len,1){
           if(num[ii]<T.num[ii])return false;
           if(num[ii]>T.num[ii])return true;
       }
       return false;
   }
   inline void operator +=(const bigNumber T){//重载+=高精度+高精度
       len=max(len,T.len);
       REP(ii,1,len){
           num[ii]+=T.num[ii];
           num[ii+1]+=num[ii]/10;
           num[ii]%=10;
       }
       while(num[len+1]){
           len++;
           num[len+1]+=num[len]/10;
           num[len]%=10;
       }
   }
   inline void operator -=(const long long TT){//重载-=高精度-单精度
       long long T=TT;
       int ii=1;
       while(T){
            num[ii]-=T%10;
            T/=10;
            ii++;
       }
   REP(ii,1,len)
       while(num[ii]<0){
            num[ii+1]--;
            num[ii]+=10;
       }
    while(num[len]==0)
            len--;
   }
   inline void operator *=(const long long T){//重载*=高精度*单精度
       REP(ii,1,len)
       num[ii]*=T;
       REP(ii,1,len){
            num[ii+1]+=num[ii]/10;
            num[ii]%=10;
       }
       while(num[len+1]){
            len++;
            num[len+1]+=num[len]/10;
            num[len]%=10;
       }
   }
inline void operator /=(const bigNumber T){////重载、=高精度/高精度
memset(tmp,0ll,sizeof(tmp));
int jj=len,tl=len;//jj,a.len  tl,t.len
len=0;   //len c.len商的位数 
while(true){
while(tl<=jj){
int jjj=jj,kkk=T.len;
while(kkk&&num[jjj]==T.num[kkk]){
jjj--;
kkk--;
}
if(kkk&&num[jjj]<T.num[kkk])
jj--;
else
break;
}
if(jj<T.len)
break;
REP(ii,jj-T.len+1,jj){//找到第一个可以放商的位置 ,jj-T.len+1 
num[ii]-=T.num[ii+T.len-jj];//减去一个除数 
if(num[ii]<0){
num[ii+1]--;
num[ii]+=10;
}
}
tmp[jj-T.len+1]++;//商加1; 
while(tl&&num[tl]==0)//去掉T的前置0; 
tl--;
len=max(len,jj-T.len+1);
}
REP(ii,1,len)
num[ii]=tmp[ii];
}
}a,b,c,d;//?????a,b 
inline bigNumber operator +(const bigNumber A,const bigNumber B){//重载+ 高精度+高精度
    bigNumber C;
    memset(C.num,0,sizeof(C.num));
    C.len=max(A.len,B.len);
    REP(ii,1,C.len)
        C.num[ii]=A.num[ii]+B.num[ii];
    REP(ii,1,C.len){
        C.num[ii+1]+=C.num[ii]/10;
        C.num[ii]%=10;
    }
    while(C.num[C.len+1]){
        C.len++;
        C.num[C.len+1]+=C.num[C.len]/10;
        C.num[C.len]%=10;
    }
    return C;
}
inline bigNumber operator -(const bigNumber A,const bigNumber B){//重载-  高精度-高精度
    bigNumber C;
    memset(C.num,0,sizeof(C.num));
    C.len=max(A.len,B.len);
    REP(ii,1,C.len)
        C.num[ii]=A.num[ii]-B.num[ii];
    REP(ii,1,C.len){
    if(C.num[ii]<0){
  C.num[ii]+=10;
           C.num[ii+1]-=1;
        }
    }
    while(C.len>1&&C.num[C.len]==0)
        C.len--;
        
    return C;
}
inline bigNumber operator *(const bigNumber A,const bigNumber B){//重载* 高精度*高精度
    bigNumber C;
    memset(C.num,0,sizeof(C.num));
    C.len=A.len+B.len-1;
    REP(ii,1,A.len)
        REP(jj,1,B.len)
            C.num[ii+jj-1]+=A.num[ii]*B.num[jj];
    REP(ii,1,C.len){
        C.num[ii+1]+=C.num[ii]/10;
        C.num[ii]%=10;
    }
    while(C.num[C.len+1]){
        C.len++;
        C.num[C.len+1]+=C.num[C.len]/10;
        C.num[C.len]%=10;
    }
    return C;
}
inline void print(const bigNumber T){
    if(T.len==0){
        printf("0");
    return;
    }
    PER(ii,T.len,1)
        printf("%lld",T.num[ii]);
    printf("\n");
}


inline long long operator %(const bigNumber A,const long long B){//重载%  高精度%单精度
    long long T=0ll;
    printf("T=%d\n",T);
    PER(ii,A.len,1)
        T=(T*10+A.num[ii])%B;
    return T;
}
inline bigNumber operator /(const bigNumber A,const long long B){//高精度/单精度 
    long long T=0ll;
    bigNumber C;
    memset(C.num,0ll,sizeof(C.num));
    C.len=A.len;
    PER(ii,A.len,1){    
        T=(T*10+A.num[ii]);
C.num[ii]=T/B;
T=T%B;
}
while(C.len>1&&C.num[C.len]==0)C.len--;   
    return C;
}


inline bigNumber operator /( bigNumber A,const bigNumber B){//高精度/高精度 
memset(tmp,0ll,sizeof(tmp));
bigNumber C,D;
int ii,jj=A.len,tl=A.len,len;//jj,A.len  tl,余数的长度 
D.len=B.len;
len=0;   //len c.len商的位数 
while(true){
/*//从被除数的左侧找到减去除数的数字段。

                while(tl<=jj){//jj代表被除数左指针的位置 
int jjj=jj,kkk=B.len;
while(kkk&&A.num[jjj]==B.num[kkk]){
jjj--;
kkk--;
}
if(kkk&&A.num[jjj]<B.num[kkk])//比较两数字大小,准备最高位的借位 
jj--;
else
break;
}
          */
                  jj=tl;//第二种方法,从被除数的左侧找到减去除数的数字段。
 D.len=B.len;
 memcpy(D.num+1,A.num+(tl-B.len+1),8*B.len);
 if(B>D)jj--;


if(jj<B.len)//除法结束 
break;
REP(ii,jj-B.len+1,jj){//找到下一个可以放商的位置 ,jj-T.len+1 
A.num[ii]-=B.num[ii+B.len-jj];//减去一个除数 
if(A.num[ii]<0){//处理借位 
A.num[ii+1]--;
A.num[ii]+=10;
}
}
tmp[jj-B.len+1]++;//商加1;商的第几位jj-T.len+1 
while(tl&&A.num[tl]==0)//去掉被除数减后的前置0; 
tl--;

len=max(len,jj-B.len+1);//记录商的最高位 
}
REP(ii,1,len)
C.num[ii]=tmp[ii];
C.len=len;
return C; 
}

inline bigNumber sqr(const bigNumber T){
    return T*T;
}
bigNumber power(const bigNumber A,const int B){
    if(B==1)
    return A;
    if(B%2)
        return sqr(power(A,B>>1))*A;
    return power(A,B>>1);
}
inline bigNumber fact(int n){
    bigNumber ans;
    ans=1ll;
    REP(ii,2,n)
        ans*=ii;
    return ans;
}
inline bigNumber max(const bigNumber A,const bigNumber B){
    if(A>B)
    return A;
    return B;
}
inline void scan(bigNumber& T){
    memset(T.num,0,sizeof(T.num));
    T.len=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    ch=getchar();
    if(ch=='0'){
        ch=getchar();
        if(ch<'0'||ch>'9')
        return;
    }
    while(ch=='0')
    ch=getchar();
    while(ch>='0'&&ch<='9'){
        T.num[++T.len]=ch-'0';
        ch=getchar();
    }
    if(T.len==1&&T.num[1]==0){
        T.len=0;
        return;
    }
    REP(ii,1,T.len>>1)
        swap(T.num[ii],T.num[T.len-ii+1]);
}




int main()
{freopen("in.txt","r",stdin); 
scan(a);
scan(b);
scan(c);
scan(d);
bigNumber ba,cba,ad,fm,fz, maxfz;
ba=b-a;
fz=c*ba;
ad=a*d;
fm=ad+fz;
memset(a.num,0,sizeof(a.num));
a.len=1002;
a.num[1002]=1;
maxfz=fz*a;
b=maxfz/fm;
memset(a.num,0,sizeof(a.num));
a.len=2;
a.num[2]=1;
if(b.num[1]>4)b+=a;
int t=1001-b.len;
printf("0.");
int ans=0;
while(t>0){
printf("0");
ans++;
t--;
}
for(int i=b.len;i>1;i--){
 ans++;
 printf("%lld",b.num[i]);
}
// printf("%d \n",ans);
}


代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值