题意:
n个甜甜圈,两个人,每次没人最多拿m个。谁先拿完谁吃掉所有当前拿的,另一个人把手上的放回,再来第二轮...
思路:
为什么不能博弈:
博弈思路:
//0~m 直接吃
//让对手是m+1,对手不管选什么,都是我们吃
//m+2~2m+1 都可以让cur为m+1,在这个范围内的可以赢
//2m+2 败
//2m+3~3m+2 胜
//3m+3 败
//
//km+k必败 -> 必败了,那我就尽可能多拿,让你少拿
// cur
// km+k
// (k-1)m+k
// (k-1)m+k-1
// (k-2)m+k-1
//
// m+1
// 1
//
// **k**
//下一轮 km
// m == 1
// 5
// 2+2
// 2+1
// 1+1
// 1
// 3
//
// 2
// 1+1
// 1
// 1
// 1
void solve()
{
cin >> n >> m;
int cur = n;
int ans = 0;
int k = 0;
while (1)
{
while (1)
{
k = cur / m;
if (cur == k * m + k)
{
cur = k * m;
}
else
{
while (cur - k * m < k)
{
k--;
}
if (cur == k * m + k)
{
cur = k * m;
continue;
}
else if (cur - k * m > k)
{
ans += cur - (k * m + k);
}
if (k <= 0)break;
ans += k;
cur = k * m;
}
break;///
}
if (k <= 0)break;
while (1)
{
k = cur / m;
if (cur == k * m + k)
{
cur = k * m;
}
else
{
while (cur - k * m < k)
{
k--;
}
if (cur == k * m + k)
{
cur = k * m;
ans += k;
continue;
}
else if (cur - k * m > k)
{
}
if (k <= 0)break;
cur = k * m;
}
break;
}
if (k <= 0)break;
}
cout << ans << endl;
}
(
我们发现当前数为 km+k时本轮必败。而其他值总可以让下一次对手取时为km+k。
但是对手赢了,下波到我们了,我们还是必败呢:
下波是km,可以是(k-1)*m + k-1
当 km == (k-1)*m + k-1 时
m == k-1
是可以发生的。
)
其实尽可能贪心了,但是无法预估下一轮是否我们是必败,要必败就亏了呀。而要处理这个,就没有普遍做法了。所以放弃吧~~
————
题解 SP122 【STEVE - Voracious Steve】 - 洛谷专栏 (luogu.com.cn)
dfs表示 [ cur ][ 先手取了多少个 ][ 后手取了多少个 ] 这种情况先手能拿的最大值。
而这种情况能取到的最大值也是 依附于 其他情况的。
这是递归。
卡时间同时每种情况答案固定,所以记忆化。
代码:
#include<string.h>
#define ll long long
//#define int long long
#define PII pair<int,int>
//纵深
const int mod = 998244353;
const int maxn = 105;
int dp[maxn][maxn][maxn];
int n, m;
int dfs(int cur, int fir, int sec)
{
if (cur == 0)//当先手可以取完时,就不需要下一轮了。
return 0;
if (dp[cur][fir][sec]>=0)
return dp[cur][fir][sec];
int ans = 0;
for (int i = 1; i <= min(m,cur-fir-sec); i++)
{
if (i + fir + sec == cur)
{
ans = max(ans, cur - dfs(sec, 0, 0));//当前减去另一个人能拿的最大值,就是我们拿的最大值
}
else
{
ans = max(ans, cur - dfs(cur,sec,fir+i));//接着拿。。?
}
}
return dp[cur][fir][sec] = ans;
}
void solve()
{
memset(dp, 255, sizeof dp);//每个字节8bit都置1,是个负数
cin >> n >> m;
cout << dfs(n, 0, 0) << endl;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}