Penney's game (hdu 5169, zoj 3274)

Penney’s game (hdu 5169, zoj 3274)

matrix67有一篇介绍Penney’s game的文章,可以看下:

http://www.matrix67.com/blog/archives/6015


Penney’s game 概率的计算方法:

假如 a 和 b 是两个 n 位 01 串。如果 a 和 b 完全相等,那么记一个数字 1 ,如果不相等,那么记一个数字 0 。接下来,比较 a 的后面 n – 1 位以及 b 的前面 n – 1 位,如果相等,那么接着记一个数字 1 ,如果不相等,那么接着记一个数字 0 。接下来,比较 a 的后 n – 2 位以及 b 的前 n – 2 位,并根据比较结果记下数字 0 或者数字 1 。不断这样做下去,直到最后比较 a 的最后面 1 位和 b 的最前面 1 位,并产生新的数字。在整个过程中,你会依次记下 n 个数字,最终会得到一个 n 位的 01 串。把它当作一个二进制数,并转换成十进制。我们把最终的结果记为 L(a, b) 。举几个例子:
L(10110, 10110) = (10010)2 = 18
L(10110, 01011) = (00001)2 = 1
L(01011, 01011) = (10000)2 = 16
L(01011, 10110) = (01001)2 = 9
那么, 01 串 a 和 b 的胜率之比就是
(L(b, b) – L(b, a)) : (L(a, a) – L(a, b))


题目:

hdu 5169

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5169

题意:

小A和小B在玩一个游戏,他们一开始每人手上都有一个01字符串,其中记小A手上的为A串,小B手上的为B串。
现在有一枚均匀的硬币,以及一个空字符串S,游戏开始后每一回合都会投掷这枚硬币,如果正面向上,就在S后面添加一个字符'1',否则添加一个字符'0'。
一旦某一回合结束时A串成为了S的子串,小A就赢了,同样如果B串成为了S的子串,小B就赢了,有一个人获得胜利时游戏结束。为了避免两个人同时胜利的情况,保证A不为B的后缀,B也不为A的后缀。
在已知A和B的情况下,这个游戏是不是公平的呢,公平意味着小A与小B拥有相同的胜率,若不公平谁更有可能赢?

限制:

1 <= |A|,|B| <= 100

思路:

因为数据量小,只有100,利用Penney’s game的结论,可以直接用java大数暴力。


/*题意:
  小A和小B在玩一个游戏,他们一开始每人手上都有一个01字符串,其中记小A手上的为A串,小B手上的为B串。
  现在有一枚均匀的硬币,以及一个空字符串S,游戏开始后每一回合都会投掷这枚硬币,如果正面向上,就在S后面添加一个字符'1',否则添加一个字符'0'。
  一旦某一回合结束时A串成为了S的子串,小A就赢了,同样如果B串成为了S的子串,小B就赢了,有一个人获得胜利时游戏结束。为了避免两个人同时胜利的情况,保证A不为B的后缀,B也不为A的后缀。
  在已知A和B的情况下,这个游戏是不是公平的呢,公平意味着小A与小B拥有相同的胜率,若不公平谁更有可能赢?
  限制:
  1 <= |A|,|B| <= 100
  思路:
  1. 首先要知道Penney’s game的结论:
  假如 a 和 b 是两个 n 位 01 串。如果 a 和 b 完全相等,那么记一个数字 1 ,如果不相等,那么记一个数字 0 。接下来,比较 a 的后面 n – 1 位以及 b 的前面 n – 1 位,如果相等,那么接着记一个数字 1 ,如果不相等,那么接着记一个数字 0 。接下来,比较 a 的后 n – 2 位以及 b 的前 n – 2 位,并根据比较结果记下数字 0 或者数字 1 。不断这样做下去,直到最后比较 a 的最后面 1 位和 b 的最前面 1 位,并产生新的数字。在整个过程中,你会依次记下 n 个数字,最终会得到一个 n 位的 01 串。把它当作一个二进制数,并转换成十进制。我们把最终的结果记为 L(a, b) 。举几个例子:
  L(10110, 10110) = (10010)2 = 18
  L(10110, 01011) = (00001)2 = 1
  L(01011, 01011) = (10000)2 = 16
  L(01011, 10110) = (01001)2 = 9
  那么, 01 串 a 和 b 的胜率之比就是
  (L(b, b) – L(b, a)) : (L(a, a) – L(a, b))

  2. 因为数据量小,只有100,可以直接用java大数暴力。
 */
import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	static final int N = 105;

	static boolean cmp(char[] a, char[] b, int len) {
		if (len > b.length)
			return false;
		boolean ret = true;
		for (int i = 0; i < len; ++i) {
			if (b[i] != a[a.length - len + i]) {
				ret = false;
				break;
			}
		}
		return ret;
	}

	static BigInteger toBigInt(char a[], int len) {
		BigInteger ret = BigInteger.ZERO;
		for (int i = len - 1; i >= 0; --i)
			ret = ret.multiply(BigInteger.valueOf(2)).add(BigInteger.valueOf(a[i] - '0'));
		return ret;
	}

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		String str;
		char[] A = new char[N];
		char[] B = new char[N];
		char[] aa = new char[N], bb = new char[N], ab = new char[N], ba = new char[N];
		BigInteger AA, BB, AB, BA;
		int ans;
		int T;
		T = in.nextInt();
		while (T-- > 0) {
			str = in.next();
			A = str.toCharArray();
			str = in.next();
			B = str.toCharArray();
			for (int i = 0; i < A.length; ++i) {
				if (cmp(A, A, i + 1))
					aa[i] = '1';
				else
					aa[i] = '0';
				if (cmp(A, B, i + 1))
					ab[i] = '1';
				else
					ab[i] = '0';
			}
			for (int i = 0; i < B.length; ++i) {
				if (cmp(B, B, i + 1))
					bb[i] = '1';
				else
					bb[i] = '0';
				if (cmp(B, A, i + 1))
					ba[i] = '1';
				else
					ba[i] = '0';
			}
			AA = toBigInt(aa, A.length);
			BB = toBigInt(bb, B.length);
			AB = toBigInt(ab, A.length);
			BA = toBigInt(ba, B.length);
			//System.out.println(AA);
			//System.out.println(AB);
			//System.out.println(BB);
			//System.out.println(BA);
			ans = BB.subtract(BA).compareTo(AA.subtract(AB));
			if (ans == 0)
				System.out.println("Fair");
			else if (ans > 0)
				System.out.println("A");
			else
				System.out.println("B");
		}
	}
}
/*
 * 1 10110 01011
 */


题目:

zoj 3274

题目链接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3274

题意:

这道题是上一道题的加强版,数据量较大。

限制:
1 <= |A|,|B| <= 100000

思路:
1. 首先要知道Penney’s game的结论:

2. 因为数据量比较大,要用kmp来优化。
kmp优化方式如下:
先算出模式串的next数组,不断地和母串的最后一位匹配,记录可以匹配的长度即可。

3. 用java大数会超时,要用c++模拟二进制大数减法。


/*题意:
  小A和小B在玩一个游戏,他们一开始每人手上都有一个01字符串,其中记小A手上的为A串,小B手上的为B串。
  现在有一枚均匀的硬币,以及一个空字符串S,游戏开始后每一回合都会投掷这枚硬币,如果正面向上,就在S后面添加一个字符'1',否则添加一个字符'0'。
  一旦某一回合结束时A串成为了S的子串,小A就赢了,同样如果B串成为了S的子串,小B就赢了,有一个人获得胜利时游戏结束。为了避免两个人同时胜利的情况,保证A不为B的后缀,B也不为A的后缀。
  在已知A和B的情况下,这个游戏是不是公平的呢,公平意味着小A与小B拥有相同的胜率,若不公平谁更有可能赢?
  限制:
  1 <= |A|,|B| <= 100000
  思路:
  1. 首先要知道Penney’s game的结论:
  假如 a 和 b 是两个 n 位 01 串。如果 a 和 b 完全相等,那么记一个数字 1 ,如果不相等,那么记一个数字 0 。接下来,比较 a 的后面 n – 1 位以及 b 的前面 n – 1 位,如果相等,那么接着记一个数字 1 ,如果不相等,那么接着记一个数字 0 。接下来,比较 a 的后 n – 2 位以及 b 的前 n – 2 位,并根据比较结果记下数字 0 或者数字 1 。不断这样做下去,直到最后比较 a 的最后面 1 位和 b 的最前面 1 位,并产生新的数字。在整个过程中,你会依次记下 n 个数字,最终会得到一个 n 位的 01 串。把它当作一个二进制数,并转换成十进制。我们把最终的结果记为 L(a, b) 。举几个例子:
  L(10110, 10110) = (10010)2 = 18
  L(10110, 01011) = (00001)2 = 1
  L(01011, 01011) = (10000)2 = 16
  L(01011, 10110) = (01001)2 = 9
  那么, 01 串 a 和 b 的胜率之比就是
  (L(b, b) – L(b, a)) : (L(a, a) – L(a, b))

  2. 因为数据量比较大,要用kmp来优化。
  kmp优化方式如下:
  先算出模式串的next数组,不断地和母串的最后一位匹配,记录可以匹配的长度即可。

  3. 用java大数会超时,要用c++模拟二进制大数减法。
 */
#include<iostream>
#include<cstdio>
using namespace std;
#define LL long long
const int N = 100050;
LL aa[N / 50], bb[N / 50], ab[N / 50], ba[N / 50];
int next[N];
void getNext(char T[], int len) {
	int i, j;
	i = 0;
	j = next[0] = -1;
	while (i < len) {
		if (j == -1 || T[i] == T[j]) next[++i] = ++j;
		else j = next[j];
	}
}
void deal(char S[], char T[], int slen, int tlen, LL res[]) {
	for (int i = 0; i <= max(slen / 50, tlen / 50); ++i) res[i] = 0;
	int i = 0, j = 0;
	if (slen >= tlen) i += slen - tlen;
	else j += tlen - slen;
	getNext(T, tlen);
	while (i < slen) {
		if (j == -1 || S[i] == T[j]) {
			++i; ++j;
			if (i == slen && j != 0) {
				int bl = (j - 1) / 50;
				int mv = (j - 1) % 50;
				res[bl] |= (1LL) << mv;
				--i;
				j = next[j - 1];
			}
		}
		else j = next[j];
	}
}
char A[N], B[N];
void print(LL a[], int len) {
	for (int i = len - 1; i >= 0; --i) {
		int bl = i / 50;
		int mv = i % 50;
		cout << ((a[bl] & (1LL << mv)) > 0) << ' ';
	}
	cout << endl;
}
void sub(LL a[], LL b[], int alen, int blen) {
	int lim = max(alen / 50, blen / 50);
	int c = 0;
	for (int i = 0; i <= lim; ++i) {
		LL tmp = a[i] - b[i] - c;
		if (tmp < 0) { c = 1, tmp += (1LL) << 50; }
		else c = 0;
		a[i] = tmp;
	}
}
int n, m;
int cmp(LL a[], LL b[], int alen, int blen) {
	int lim = max(alen / 50, blen / 50);
	int ret = 0;
	for (int i = lim; i >= 0; --i) {
		if (a[i] > b[i]) { ret = 1; break; }
		if (a[i] < b[i]) { ret = -1; break; }
	}
	return ret;
}
void gao() {
	int fa, fb;
	sub(bb, ba, m, m);
	sub(aa, ab, n, n);
	int ans = cmp(bb, aa, m, n);
	if (ans == 0) puts("Equal");
	else if (ans == 1) puts("Hamlet");
	else puts("Laertes");
}
int main() {
	while (scanf("%d%d", &n, &m) && (n || m)) {
		scanf("%s%s", A, B);
		deal(A, A, n, n, aa);
		deal(B, B, m, m, bb);
		deal(A, B, n, m, ab);
		deal(B, A, m, n, ba);

		//print(aa, n);
		//print(ab, n);
		//print(bb, m);
		//print(ba, m);
		gao();
	}
	return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值