2023牛客多校第一场 - D J

牛客多校第一场

比赛地址:传送门
D 博弈
J 概率递推式(需优化)

题解搜集:
https://zhuanlan.zhihu.com/p/644609639


D 题

题意:
有一个 \(n \times m\) 的网格,每格放了块巧克力。Walk Alone(懵哥)和 Kelin 轮流吃巧克力,Kelin 先吃。每轮一个人能选择一个左下角为(1,1)的子矩形,把里面的巧克力吃光,且至少要吃一个,吃到最后一个巧克力的人输。问懵哥和 Kelin 谁赢。

思路:
1x1后手赢,其他情况先手赢。怎么理解?依旧是必胜态与必败态的转移。
是个chomp游戏,详见链接:传送门
感觉emmm,一般性的必胜策略难以证明,有些特殊情况的则即为简单,例如 n=m 、n=1 或 m=1(不同时成立)、n=2 或 m=2(不同时成立)时均有非常简单的必胜策略。其余情况打的时候就没推出来。。。
离散数学偏序关系?坏了,之前没学好离散数学

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long

using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*
1x1后手赢,其他情况先手赢
*/
const int maxm=2e5+5,inf=0x3f3f3f3f,mod=998244353;

void solve(){
	int n,m;
	cin>>n>>m;
	if(n==1 && m==1) cout<<"Walk Alone\n";
	else cout<<"Kelin\n";
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
	// cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

H 题

题解(来自changge)
还有个22级的离谱思路,双重循环+限制循环次数即得解,估计是数据太水了~

J 题

题意:
Walk Alone 在玩一种赌博游戏,游戏的规则和步骤如下:

  • 整局游戏有很多轮
  • 每一轮,Walk Alone 都可以支付 \(x_i\) 元作为自己的赌资。如果说Walk Alone 赢下了这一轮,那么他将获得 \(2x_i\) 元;如果 Walk Alone 输了,赌资就没了。赢得概率规定为0.5。

Walk Alone 初始有 n 元本金,他想要再赚 m 元,他有自己的策略去参与这场赌博:

  • 第一轮,Walk Alone 只会支付赌资 \(x_1 = 1\)
  • 如果 Walk Alone 在第 i-1 轮赢了,那么第 i 轮 \(x_i = 1\);反之,输了的话 \(x_i = 2x_{i-1}\)
  • 每一轮的开始,如果说 Walk Alone 已经拥有的钱数大于等于 n+m ,则他就退出比赛;否则,他必须将 \(x_i\) 作为自己的赌资,如果他没有 \(x_i\) 元则将被迫退出比赛。

问你 Walk Alone 最终获胜的概率?
思路:
概率递推式
打时具体的过程都想清楚了,但是欠点实现的思路qwq
第 i 轮 :直接赢,赚 1 块;假设能输的情况下,输 lg 场后赢,也是赢 1 元,所以想要赢钱的可能就是“输输输...输赢”,输的次数取决于最大能输的次数。假设当前持有金额为 k ,则 Walk Alone 最多能输 \(lg = \log_2(k + 1)\) 轮,此时赢的概率即为 $P_i=1 - \frac{1}{2^{lg}} $
那么从本金 n 到最终结束的金额 n + m 之间的概率均已知,最终的概率为 \(\prod_{i=n}^{n+m}{P_i}\)
之后我们注意到,对于\([2^j - 1, 2^{j+1} - 2]\)之间的持有钱数的输场次数是相等的,所以可以利用这个进行优化计算
具体的代码还可以再看看,小细节再理解理解
下为代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long

using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*

*/
const int maxm = 2e5+5, inf = 0x3f3f3f3f, mod = 998244353;

ll qpow(ll a,ll x){
	ll res = 1;
	while(x){
		if(x & 1) res = res * a % mod;
		a = a * a % mod;
		x >>= 1;
	}
	return res;
}

void solve(){
	ll n, m;
	cin >> n >> m;
	ll t = n, ans = 1;
	while(t < n + m){
		ll lg = log2(t + 1), r = min(m + n, (1ll << (lg + 1)) - 1);
		ans *= qpow(mod + 1 - qpow(2, mod - 1 - lg), r - t);
		ans %= mod;
		t = r;
	}
	cout << ans <<'\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	// cin >> _;
	while(_--){
		solve();
	}
	return 0;
}

K 题

题意:

思路:

posted on 2023-07-19 16:57  Qiansui  阅读(49)  评论(0编辑  收藏  举报