【题目大意】
一个口袋里装了t种颜色的球,第i种颜色的球的数目为a[i],每次随机抽一个小球,然后再放d个这种颜色的小球进口袋。
给出n个要求,第x个抽出的球颜色为y,求满足条件的概率。
【思路分析】
抽出一个球颜色为i的概率设为f[i],球的总数为sum
在第k步时,$f[i]=frac{a[i]}{sum}$
那么在k+1步就有两种情况:
1.第k步抽中了颜色为i的球,那么此时概率为$frac{a[i]}{sum}*frac{a[i]+d}{sum+d}$
2.第k步没有抽中,那么此时概率为$(1-frac{a[i]}{sum})*frac{a[i]}{sum+d}$
所以第k+1步时,$f[i]=(1-frac{a[i]}{sum})*frac{a[i]}{sum+d}+frac{a[i]}{sum}*frac{a[i]+d}{sum+d}=frac{a[i]*(sum-a[i]+a[i]+d)}{sum*(sum+d)}=frac{a[i]}{sum}$
由此可得,在任意时刻抽到某一种颜色的小球的概率是不变的,始终为$frac{a[i]}{sum}$
如果这道题没有条件的话,到这里就可以完美解决了,但是我们还要考虑题目的条件。
这里有一个结论:要求中某一步要取的颜色出现的顺序对概率并没有影响。
假设现在的两个要求中的小球颜色分别为i,j
1.若i在前,概率$P1=frac{a[i]}{sum}*frac{a[j]}{sum+d}$
2.若j在前,概率$P2=frac{a[j]}{sum}*frac{a[i]}{sum+d}$
显然,$P1=P2=frac{a[i]*a[j]}{sum*(sum+d)}$,得证。
然后写代码的时候还要注意一点就是那个概率的数字可能会很大,所以要先分解质因数约分一下。
【代码实现】
1 #include<bits/stdc++.h> 2 #define go(i,a,b) for(register int i=a;i<=b;i++) 3 #define back(i,a,b) for(register int i=a;i>=b;i--) 4 #define ll long long 5 using namespace std; 6 int fr(){ 7 int w=0,q=1; 8 char ch=getchar(); 9 while(ch>'9'||ch<'0'){ 10 if(ch=='-') q=-1; 11 ch=getchar(); 12 } 13 while(ch>='0'&&ch<='9') 14 w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); 15 return w*q; 16 } 17 int prime[20002],num=0; 18 int t,n,d; 19 int a[1002],sum,ans1[20002],ans2[20002]; 20 int A1[20002],A2[20002]; 21 void Prime(){//找质数 22 int v[20002]; 23 memset(v,0,sizeof(v)); 24 go(i,2,20000){ 25 if(!v[i]) v[i]=i,prime[++num]=i; 26 go(j,1,num){ 27 if(i*prime[j]>20000||prime[j]>v[i]) break; 28 v[i*prime[j]]=prime[j]; 29 } 30 } 31 return; 32 } 33 void yue(int *ans,int x){//约分 34 go(i,1,num){ 35 if(x<prime[i])break; 36 while(x%prime[i]==0) 37 ans[i]++,x/=prime[i]; 38 } 39 return; 40 } 41 void add(int *ans,int x,int &len){ 42 go(i,1,len) ans[i]*=x; 43 go(i,1,len) ans[i+1]+=ans[i]/10,ans[i]%=10; 44 while(ans[len+1]) 45 len++,ans[len+1]+=ans[len]/10,ans[len]%=10; 46 return; 47 } 48 void mul(int *ans,int *x,int &len){//把约分后的数乘起来 49 go(i,1,num) 50 while(x[i]) add(ans,prime[i],len),x[i]--; 51 return; 52 } 53 int main(){ 54 t=fr();n=fr();d=fr(); 55 go(i,1,t) a[i]=fr(),sum+=a[i]; 56 Prime(); 57 go(i,1,n){ 58 int y=fr();y=fr(); 59 if(!a[y]){printf("0/1");return 0;} 60 yue(ans1,a[y]);yue(ans2,sum);sum+=d;a[y]+=d; 61 } 62 go(i,1,num){ 63 int cut=min(ans1[i],ans2[i]); 64 ans1[i]-=cut;ans2[i]-=cut; 65 } 66 A1[1]=A2[1]=1;int len1=1,len2=1; 67 mul(A1,ans1,len1);mul(A2,ans2,len2); 68 back(i,len1,1) printf("%d",A1[i]); 69 printf("/"); 70 back(i,len2,1) printf("%d",A2[i]); 71 return 0; 72 }