●BZOJ 1416 [NOI2006]神奇的口袋

Posted *ZJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了●BZOJ 1416 [NOI2006]神奇的口袋相关的知识,希望对你有一定的参考价值。

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=1416
题解:

Pòlya瓦罐模型:
给定罐子里每种颜色的球的个数A[i],按题目要求随机操作若干次之后,摸到i号球的概率仍然为A[i]/sum(A[i])。

所以可以把题目看成若干次这种游戏,得出每次取球时的概率,然后更新对应的A[i]和sum(A[i])。
把每次的概率相乘即是答案。

要用到高精度,为了避免除法,可以先把分子分母质因数分解(最大质因子不超过20000),
把分子分母相同的因子相互抵消后,再用高精度乘起来。


代码:

 

#include<bits/stdc++.h>
#define BIT 10000
#define MAXN 1005
using namespace std;
struct Bigint{
	int A[2*MAXN],len;
	Bigint(){memset(A,0,sizeof(A)); len=1;}
	void operator = (int rtm){
		*this=Bigint();
		do{
			A[len++]=rtm%BIT; rtm/=BIT;
		}while(rtm);
		len--;
	}
	Bigint operator * (const Bigint &rtm) const{
		static Bigint now; now=Bigint();
		for(int i=1;i<=len;i++)
			for(int j=1;j<=rtm.len;j++){
				now.A[i+j-1]+=A[i]*rtm.A[j];
				now.A[i+j]+=now.A[i+j-1]/BIT;
				now.A[i+j-1]%=BIT;
			}
		now.len=len+rtm.len;
		while(!now.A[now.len]) now.len--;
		return now;
	}
	Bigint operator ^ (int b){
		static Bigint now,base;
		base=*this; now=1;
		while(b){
			if(b&1) now=now*base;
			b>>=1; base=base*base;
		}
		return now;
	}
	void Print(){
		printf("%d",A[len]);
		for(int i=len-1;i;i--)
			printf("%04d",A[i]);
	}
};
int T,N,D,S,pnt;
int A[MAXN],prime[20005],cnt[2][20005];
void prework(){
	static bool np[20005];
	for(int i=2;i<=20000;i++) if(!np[i]){
		prime[++pnt]=i; 
		for(int j=i*i;j<=20;j+=i) np[j]=1;
	}
}
void Decomposition(int k,int val){
	static int mincnt;
	if(val&&cnt[k][0]!=0) cnt[k][0]=1;
	else return (void)(cnt[k][0]=0);
	for(int i=1;i<=pnt&&val!=1;i++){
		while(val%prime[i]==0)
			cnt[k][i]++,val/=prime[i];
		mincnt=min(cnt[k][i],cnt[k^1][i]);
		cnt[k][i]-=mincnt; cnt[k^1][i]-=mincnt;
	}
}
Bigint combination(int k){
	Bigint ret,tmp; ret=cnt[k][0];
	for(int i=0;i<=pnt;i++) if(cnt[k][i]){
		tmp=prime[i];
		tmp=tmp^cnt[k][i];
		ret=ret*tmp;
	}
	return ret;
}
int main(){
	prework(); prime[0]=1;
	cnt[0][0]=cnt[1][0]=-1;
	scanf("%d%d%d",&T,&N,&D);
	for(int i=1;i<=T;i++)
		scanf("%d",&A[i]),S+=A[i];
	for(int i=1,x,y;i<=N;i++){
		scanf("%d%d",&x,&y);
		Decomposition(0,A[y]);
		Decomposition(1,S);
		A[y]+=D; S+=D;
	}
	Bigint a=combination(0);
	Bigint b=combination(1);
	if(!cnt[0][0]) b=1;
	a.Print(); putchar(‘/‘);
	b.Print(); putchar(‘\n‘);
	return 0;
}

 

  

 

以上是关于●BZOJ 1416 [NOI2006]神奇的口袋的主要内容,如果未能解决你的问题,请参考以下文章

[NOI2006]神奇口袋

bzoj1479[NOI2006]最大获利

BZOJ 1497: [NOI2006]最大获利

bzoj1497NOI2006最大获利

bzoj 1497: [NOI2006]最大获利

BZOJ 2006: [NOI2010]超级钢琴