「BJOI2018」双人猜数游戏(博弈+dp)
不知道很多轮后就知道了是因为可能的数对在不断减少。
考虑设\(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("\n")
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\n", 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\n", x, y);
return;
}
}
}
}
}
}
int main() {
fo(T, 1, 25) {
fprintf(stderr, "%d\n", T);
init(T);
freopen(in.c_str(), "r", stdin);
freopen(out.c_str(), "w", stdout);
work();
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址