Bzoj1498&1416: [NOI2006]神奇的口袋

什么鬼双倍经验题???


Sol

考虑在第\(k\)次摸到\(y\)的概率

  • 如果上次摸到\(y\),目前有\(sum\)个球,\(y\)\(a[y]\)个,那么概率就是\(\frac{a[y]+d}{sum+d}*\frac{a[y]}{sum}\)
  • 如果上次没摸到\(y\),那么概率就是\(\frac{a[y]}{sum+d}*\frac{sum-a[y]}{sum}\)

合在一起就是\(\frac{a[y]}{sum}\)

那么就是直接这样写

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(2005);
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int t, n, d, a[_], sum;
ll p1 = 1, p2 = 1;

IL ll Gcd(RG ll x, RG ll y){
    return !y ? x : Gcd(y, x % y);
}

int main(RG int argc, RG char* argv[]){
    t = Input(), n = Input(), d = Input();
    for(RG int i = 1; i <= t; ++i) a[i] = Input(), sum += a[i];
    for(RG int i = 1, y; i <= n; ++i){
        Input(), y = Input();
        p1 *= a[y], p2 *= sum;
        sum += d, a[y] += d;
    }
    RG ll d = Gcd(p1, p2);
    printf("%lld/%lld\n", p1 / d, p2 / d);
    return 0;
}

然后显然要高精度,为防止高精度\(Gcd\)
所以可以直接分解质因数,然后乘法

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(2005);
const int __(2e5 + 1);
const int SZ(1e4);
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int t, n, d, a[_], sum;
int prime[__], num, isprime[__];
struct Int{
	int fac[__], len, a[__];

	IL void Add(RG int x){
		for(RG int i = 1; i <= num && prime[i] <= x; ++i)
			while(!(x % prime[i])) x /= prime[i], ++fac[i];
	}

	IL void Mul(RG int x){
		RG int ud = 0;
		for(RG int i = 1; i <= len; ++i)
			a[i] = a[i] * x + ud, ud = a[i] / SZ, a[i] %= SZ;
		while(ud) a[++len] = ud % SZ, ud /= SZ;
	}

	IL void Print(){
		printf("%d", a[len]);
		for(RG int i = len - 1; i; --i) printf("%04d", a[i]);
	}
} P1, P2;

IL void Sieve(){
	isprime[1] = 1;
	for(RG int i = 2; i < __; ++i){
		if(!isprime[i]) prime[++num] = i;
		for(RG int j = 1; j <= num && i * prime[j] < __; ++j){
			isprime[i * prime[j]] = 1;
			if(!(i % prime[j])) break;
		}
	}
}

int main(RG int argc, RG char* argv[]){
	Sieve(), P1.len = P2.len = P1.a[1] = P2.a[1] = 1;
	t = Input(), n = Input(), d = Input();
	for(RG int i = 1; i <= t; ++i) a[i] = Input(), sum += a[i];
	for(RG int i = 1, y; i <= n; ++i){
		Input(), y = Input();
		if(!a[y]) return puts("0/1"), 0;
		P1.Add(a[y]), P2.Add(sum);
		sum += d, a[y] += d;
	}
	for(RG int i = 1; i <= num; ++i){
		if(P2.fac[i] >= P1.fac[i]) P2.fac[i] -= P1.fac[i], P1.fac[i] = 0;
		else P1.fac[i] -= P2.fac[i], P2.fac[i] = 0;
		for(RG int j = 1; j <= P1.fac[i]; ++j) P1.Mul(prime[i]);
		for(RG int j = 1; j <= P2.fac[i]; ++j) P2.Mul(prime[i]);
	}
	P1.Print(), putchar('/'), P2.Print();
    return puts(""), 0;
}
posted @ 2018-04-03 13:53  Cyhlnj  阅读(166)  评论(1编辑  收藏  举报