scarlyw的博客

如果世界真的不喜欢你,那世界就是我的敌人了。

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;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/scar_lyw/article/details/80288727
文章标签: NOI 提交答案 DP
想对作者说点什么? 我来说一句

BJ模拟2017 D1T1 计数

DP

scar_lyw scar_lyw

2018-05-13 15:32:30

阅读数:34

没有更多推荐了,返回首页

不良信息举报

NOI模拟(5.11) BJOID2T1 双人猜数游戏

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭