【LOJ】#2511. 「BJOI2018」双人猜数游戏

题解

\(f[p][a][b]\)表示询问了\(p\)次,答案是\(a,b\)是否会被猜出来

然后判断如果\(p = 1\)
第一个问的\(Alice\),那么\([s,\sqrt{nm}]\)约数只有一个,\(f[p][a][b] = 1\)否则为\(0\)
如果第一个问的\(Bob\),那么\(a + b - 2 * S <= 1\)那么\(f[p][a][b] = 1\)否则为\(0\)

剩下的按照\(p\)这次操作询问谁,且然后从可能的数对里找\(f[p - 1][i][j]\)\(0\)的有几个,如果只有1个就猜出来了

同时还要保证,在某个人猜出来之后,另一个猜出来的人询问第\(T + 1\)回合刚好能被猜出来的数对中,也只会问出一个,那么答案就是\(a,b\)

用记搜,跑得还是挺快的

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 20005
#define eps 1e-8
#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 + c - '0';
	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
	out(x / 10);
    }
    putchar('0' + x % 10);
}
int f[25][505][505],cnt[505 * 505],g[505][505];
vector<int> v[505 * 505];
int S,T,k;
char c[25];
bool dp(int p,int a,int b) {
    if(p == 0) return 0;
    if(f[p][a][b] != -1) return f[p][a][b];
    if(p == 1) {
	if(k == 1) {
	    
	    if(cnt[a * b] > 1) f[p][a][b] = 0;
	    else f[p][a][b] = 1;
	}
	else {
	    if(a + b - 2 * S <= 1) f[p][a][b] = 1;
	    else f[p][a][b] = 0;
	}
	return f[p][a][b];
    }
    if(dp(p - 1,a,b)) return f[p][a][b] = 1;
    if(p % 2 == k) {
	int c = 0;
	for(auto h : v[a * b]) {
	    if(!dp(p - 1,h,a * b / h)) ++c;
	}
	if(c == 1) f[p][a][b] = 1;
	else f[p][a][b] = 0;
    }
    else {
	int c = 0;
	for(int i = S ; i <= (a + b) / 2 ; ++i) {
	    if(!dp(p - 1,i,a + b - i)) ++c;
	}
	if(c == 1) f[p][a][b] = 1;
	else f[p][a][b] = 0;
    }
    return f[p][a][b];
}
bool check(int a,int b) {
    if(g[a][b] != -1) return g[a][b];
    int c = 0;
    if((T + 2) % 2 == k) {
	for(auto h : v[a * b]) {
	    if(dp(T + 1,h,a * b / h) && !dp(T,h,a * b / h)) ++c;
	}
    }
    else {
	for(int i = S ; i <= (a + b) / 2 ; ++i) {
	    if(dp(T + 1,i,a + b - i) && !dp(T,i,a + b - i)) ++c;
	}
    }
    if(c == 1) g[a][b] = 1;
    else g[a][b] = 0;
    return g[a][b];
}
pii Solve() {
    memset(f,-1,sizeof(f));
    memset(cnt,0,sizeof(cnt));
    memset(g,-1,sizeof(g));
    for(int i = S * S ; i <= 500 * 500 ; ++i) {
	int t = sqrt(i);
	v[i].clear();
	for(int j = S ; j <= t ; ++j) {
	    if(i % j == 0) {
		cnt[i]++;
		v[i].pb(j);
	    }
	}
    }
    for(int s = S + S ; s <= 1000 ; ++s) {
	for(int i = S ; i <= 500 ; ++i) {
	    if(i > s) break;
	    for(int j = i ; j <= s - i ; ++j) {
		if(i + j > s) break;
		if(dp(T + 1,i,j) && !dp(T,i,j) && check(i,j)) {return mp(i,j);}
	    }
	}
    }
}
int main() {
    for(int i = 1 ; i <= 25 ; ++i) {
	stringstream ss;
	string num;
	ss << i;
	ss >> num;
	string str1 = "guess/guess" + num + ".in";
	FILE *fin = fopen(str1.c_str(),"r");
	fscanf(fin,"%d%s%d",&S,c + 1,&T);
       
	string str2 = "answer/guess" + num + ".out";
	FILE *fout = fopen(str2.c_str(),"w");
	if(c[1] == 'A') k = 1;
	else k = 0;
	pii ans = Solve();
	fprintf(fout,"%d %d\n",ans.fi,ans.se);
	printf("OK with %d task\n",i);
    }
    return 0;
}
posted @ 2018-11-20 19:18  sigongzi  阅读(462)  评论(0编辑  收藏  举报