雙人猜數遊戲
題目背景:
分析:DP
沒想到省選還有題答題,沒想到省選第一道就是題答,雖然最後還是像做傳統題,一開始拿到題非常懵逼,爲什麼說了幾個不知道就知道了,感覺很奇葩,然後自己思考了一下t = 2的情況,首先如果Bob第一輪說不知道,就說明肯定不是最小的數乘二,或者最小的兩個數相加,而Alice第一次說不知道,就是說,不是可以在S以上的數中分解成兩種形式的,當時考場上沒有想到那麼多,直接機打 + 手玩了前10個點,具體就是電腦分解質因數我來手算方案······然後期望40,實際28,原因是有三個點會出現其中一個知道了,另一個不知道的情況,要反向判定一下。考慮對於所有點怎麼做,對於其中一個人,對於上一個人的不知道,應該得到的信息就是,可能的解是上一個人在上一輪依然不能確定的方案,那麼我們定義dp[i][j][k]表示i, j在k輪之後能不能被確定,那麼對於第i + 1輪,如果是Bob,那麼dp[i][j][k + 1]的取值就應該是首先看dp[i][j][k - 1]是否已經確定,如果沒有,那麼就是枚舉i + j可能的分解方式(s, i + j - s), (s + 1, i + j - s - 1)······如果dp[i][j][k] == 0的只有一個,那麼說明這一對i + j是可以確定的了,如果對於i + j上一輪不能確定的不止1個,那麼i, j就依然不能確定。如果i + 1輪是Alice,同理分析就可以了,將i + j變成i * j,然後最後爲了防止出現一個人知道了,但是另一個人不知道的情況,我們需要反向判定一下,就是判定第t輪後對方知道了,但是t - 2輪時並不知道的是否只有1個,就可以了,可以用一個DP來實現一下,代碼非常好寫,複雜度什麼的····並不重要,總之大概半個小時左右就能跑完。下面的代碼就是用來跑答案的。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
inline char read() {
static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}
// /*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}
template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}
inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int MAXN = 2000 + 15;
const int MAXM = 20 + 3;
int s, t;
bool dp[MAXN][MAXN][MAXM];
char p[10];
inline bool check1(int x, int y, int t) {
int c = x + y, p1 = 0, p2 = 0, cnt = 0;
for (int i = s; i <= c / 2; ++i) {
if (t == 0 || dp[i][c - i][t - 1] == 0)
p1 = i, p2 = c - i, cnt++;
}
return (cnt == 1 && p1 == x && p2 == y);
}
inline bool check2(int x, int y, int t) {
int c = x * y, p1 = 0, p2 = 0, cnt = 0;
for (int i = s, end = sqrt(c); i <= end; ++i) {
if (c % i == 0) {
if (t == 0 || dp[i][c / i][t - 1] == 0)
p1 = i, p2 = c / i, cnt++;
}
}
return (cnt == 1 && p1 == x && p2 == y);
}
inline bool able1(int x, int y, int t) {
int c = x + y, p1 = 0, p2 = 0, cnt = 0;
for (int i = s; i <= c / 2; ++i) {
if (dp[i][c - i][t] == 1 && (t < 2 || dp[i][c - i][t - 2] == 0))
p1 = i, p2 = c - i, cnt++;
}
return (cnt == 1 && p1 == x && p2 == y);
}
inline bool able2(int x, int y, int t) {
int c = x * y, p1 = 0, p2 = 0, cnt = 0;
for (int i = s, end = sqrt(c); i <= end; ++i) {
if (c % i == 0)
if (dp[i][c / i][t] == 1 && (t < 2 || dp[i][c / i][t - 2] == 0))
p1 = i, p2 = c / i, cnt++;
}
return (cnt == 1 && p1 == x && p2 == y);
}
inline void dfs(int s, int t, bool flag) {
for (int i = 0; i <= t; ++i, flag ^= 1) {
for (int j = s; j <= 1000; ++j)
for (int k = s; k <= 1000; ++k) {
if (i >= 2) dp[j][k][i] = dp[j][k][i - 2];
dp[j][k][i] |= (flag ? check1(j, k, i) : check2(j, k, i));
}
}
}
inline void solve() {
scanf("%d%s%d", &s, p, &t);
dfs(s, t, (p[0] == 'B'));
for (int i = 2 * s; ; ++i) {
for (int j = s; j <= i / 2; ++j) {
int x = j, y = i - j;
bool flag = true;
for (int k = 0; k < t; ++k)
if (dp[x][y][k] == true) {
flag = false;
break ;
}
if (dp[x][y][t] == false) flag = false;
if (!flag) continue ;
if (t & 1) flag = (p[0] == 'A') ? (able2(x, y, t))
: (able1(x, y, t));
else flag = (p[0] == 'A') ? (able1(x, y, t)) : (able2(x, y, t));
if (!flag) continue ;
std::cout << x << " " << y, exit(0);
}
}
}
int main() {
freopen("in.in", "r", stdin);
solve();
return 0;
}