「BJOI2018」双人猜数游戏(博弈+dp)

https://loj.ac/problem/2511

不知道很多轮后就知道了是因为可能的数对在不断减少。

考虑设(f[z][x][y])表示(z)轮后,两个数分别为(x,y)是否能猜出来。

(z=1)时,(f=可能的数对(u,v)只有一个)

(z>1)
转移1:(f[z][x][y]=f[z-2][x][y])
转移2:枚举所有可能的数对((u,v)),若((u,v)(除(x,y)))(z-1)轮都被猜出来,则(f[z][x][y]=1)

最后,答案要的是两个人都知道的时间是(t+1)(t+2)

((x,y))合法的条件:
((x,y))最早知道时间是(t+1),且对于所有可能的数对((u,v)),只有((x,y))(t+1)知道,那么(t+2)时另一人就可以知道。

利用记忆话搜索+map可以(1s)内出所有解,

Code

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;

string in, out, num;

void init(int t) {
	num = "";
	for(; t; t /= 10) num = ((char) (t % 10 + '0')) + num;
	in = "guess" + num + ".in";
	out = "guess" + num + ".out";
}

int s, t; char str[105];

const int N = 100005;

map<int, int> bz[18][N], f[18][N];

int dg(int z, int x, int y) {
	if(bz[z][x][y]) return f[z][x][y];
	bz[z][x][y] = 1;
	if(z == 1) {
		if(str[0] == 'A') {
			int cnt = 0;
			fo(i, s, x * y) if(x * y % i == 0 && i <= x * y / i)
				cnt ++;
			f[z][x][y] = cnt == 1;
		} else {
			int cnt = 0;
			fo(i, s, x + y) if(i <= x + y - i)
				cnt ++;
			f[z][x][y] = cnt == 1;
		}
		return f[z][x][y];
	}
	f[z][x][y] = z > 2 ? dg(z - 2, x, y) : 0;
	if(!f[z][x][y]) {
		if(((str[0] == 'A') + z) % 2 == 0) {
			int cnt = 0;
			fo(i, s, x * y) if(x * y % i == 0 && i <= x * y / i) {
				cnt += !dg(z - 1, i, x * y / i);
			}
			if(cnt == 1 && !dg(z - 1, x, y))
				f[z][x][y] = 1;
		} else {
			int cnt = 0;
			fo(i, s, x + y) if(i <= x + y - i) {
				cnt += !dg(z - 1, i, x + y - i);
			}
			if(cnt == 1 && !dg(z - 1, x, y))
				f[z][x][y] = 1;
		}
	}
	return f[z][x][y];
}

int n;

int qry(int x, int y) {
	fo(i, 1, t + 1) if(dg(i, x, y))
		return i;
	return -1;
}

void work() {
	fo(i, 1, 17) fo(j, 1, 1e5) bz[i][j].clear();
	scanf("%d", &s);
		scanf("%s", str);
		scanf("%d", &t);
		fo(sum, 2 * s, 100000) {
			fo(x, s, sum / 2) {
				int y = sum - x;
				if(qry(x, y) == t + 1) {
					int cnt = 0;
					if(((str[0] == 'A') + t) % 2 == 0) {
						int cnt = 0;
						fo(i, s, x * y) if(x * y % i == 0 && i <= x * y / i) {
							cnt += (qry(i, x * y / i) == (t + 1));
						}
						if(cnt == 1) {
							pp("%d %d
", x, y);
							return;
						}
					} else {
						int cnt = 0;
						fo(i, s, x + y) if(i <= x + y - i) {
							cnt += (qry(i, x + y - i) == (t + 1));
						}
						if(cnt == 1) {
							pp("%d %d
", x, y);
							return;
						}
						
					}
				}
			}
		}
}

int main() {
	fo(T, 1, 25) {
		fprintf(stderr, "%d
", T);
		init(T);
		freopen(in.c_str(), "r", stdin);
		freopen(out.c_str(), "w", stdout);
		work();
	}
	
}
原文地址:https://www.cnblogs.com/coldchair/p/12696822.html