CF2217F 思路分享(博弈论,nim 游戏,数位 dp)

https://codeforces.com/problemset/problem/2217/F

题意

初始有两个区间,\([l_1,r_1]\)\([l_2,r_2]\),每次操作选择一个区间,将 \(l\) 向左移动任意距离,或将 \(r\) 向右移动任意距离(二者只能选一个),必须时刻满足 \(1\le l_1 \le r_1 \le x_1\)\(1\le l_2 \le r_2 \le x_2\).

初始给定 \(x_1,x_2\)\(A\) 可以指定 \([l_1,r_1]\),而 \([l_2,r_2]\) 随机生成,\(A\) 先手,无法进行操作者输,求让 \(A\) 赢概率最大的 \([l_1,r_1]\).

\(1\le x_1,x_2 \le 5\cdot 10^5\).

思路

相当于四堆石子的 \(nim\) 游戏,记石子数量分别为 \(a_1,a_2,a_3,a_4\).

可以指定 \(a_1,a_2\),满足 \(a_1+a_2 \lt x_1\),令 \(t=a_1\oplus a_2\),相当于可以指定 \(t\).

\(t\in [0,x_1-1]\),一种合法的构造是 \(a_1 = 0,a_2 = t\).

枚举 \(t\),求出满足 \(t\oplus a_3 \oplus a_4=0\) 的数量,取最少的即可.

问题转化成求

\[\begin{cases} a_3 + a_4 \le x_2-1 \\ a_3 \oplus a_4 = t \end{cases} \]

的数量.

位数是 \(log\) 级别,考虑数位 \(dp\).

加法的进位不好处理,作如下转化

\[a_3 + a_4 = a_3 \oplus a_4 + 2(a_3 \And a_4) = t+2(a_3 \And a_4) \]

\(s = \left\lfloor\frac{x_2-1-t}{2}\right\rfloor\),因此 \(a_3 \And a_4 \le s\).

注意特判掉 \(x_1 \gt x_2\) 的情况.

时间复杂度 \(\mathcal{O}(n\log V)\)\(V\)\(x_1,x_2\) 的上界.

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll INF = 9e18;

void solve(){
	int x1,x2;
	cin >> x1 >> x2;

	if (x1>x2){
		cout << 1 << ' ' << 1 << '\n';
		return;
	}

	int pos = -1;
	ll minn = INF;
	for (int t=0;t<=x1-1;t++){
		int s = (x2-1-t)/2;
		array<ll,2> dp = {0,1};
		for (int i=20;i>=0;i--){
			array<ll,2> ndp = {0,0};
			for (int j=0;j<=1;j++){
				for (int u=0;u<=1;u++){
					for (int v=0;v<=1;v++){
						if ((u^v)!=(t>>i&1) || j==1 && (u&v)>(s>>i&1)) continue;
						int nj = j && (u&v)==(s>>i&1);
						ndp[nj] += dp[j];
					}
				}
			}
			dp = ndp;
		}
		if (dp[0]+dp[1]<minn){
			minn = dp[0]+dp[1];
			pos = t;
		}
	}

	cout << 1 << ' ' << x1-pos << '\n';
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t = 1;
	cin >> t;
	while (t--) solve();

	return 0;
}
posted @ 2026-07-03 19:40  kzssCCC  阅读(6)  评论(0)    收藏  举报