双人猜数游戏
题目背景:
分析: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; }