NOI模擬(5.11) BJOID2T1 雙人猜數遊戲

雙人猜數遊戲

題目背景:

5.11 模擬 BJOI2018D2T1

分析:DP

 

沒想到省選還有題答題,沒想到省選第一道就是題答,雖然最後還是像做傳統題,一開始拿到題非常懵逼,爲什麼說了幾個不知道就知道了,感覺很奇葩,然後自己思考了一下t = 2的情況,首先如果Bob第一輪說不知道,就說明肯定不是最小的數乘二,或者最小的兩個數相加,而Alice第一次說不知道,就是說,不是可以在S以上的數中分解成兩種形式的,當時考場上沒有想到那麼多,直接機打 + 手玩了前10個點,具體就是電腦分解質因數我來手算方案······然後期望40,實際28,原因是有三個點會出現其中一個知道了,另一個不知道的情況,要反向判定一下。考慮對於所有點怎麼做,對於其中一個人,對於上一個人的不知道,應該得到的信息就是,可能的解是上一個人在上一輪依然不能確定的方案,那麼我們定義dp[i][j][k]表示i, jk輪之後能不能被確定,那麼對於第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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章