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;
}

浙公网安备 33010602011771号