「CF1033G」Chip Game 题解

本文网址:https://www.cnblogs.com/zsc985246/p/17331425.html ,转载请注明出处。

传送门

「CF1033G」Chip Game

题目大意

n 个石子堆,每堆有 ai 个石子。A 与 B 轮流取,A 每次只能取 x 个,B 每次只能取 y 个。

求对于所有 x,y[1,m],A 必胜、B 必胜、先手必胜和后手必胜的数量。

n100,m105,ai1018

思路

A 必胜和 B 必胜本质是相同的。所以我们只需要考虑先手必胜和后手必胜。

我们很容易猜到将数组对 x+y 取模。

如果取模后的状态先手必胜,那么先手第一步按照取模后的必胜策略进行,之后一直与后手拿同一堆,变为取模后的局面。那么这样原状态先手必胜。

如果取模后的状态后手必胜,后手可以一直拿与先手相同的堆,变为取模后的局面。此时原状态后手必胜。

所以取模后的局面与原局面必胜状态相同。

我们先假设 xy

我们取模之后会出现四种类型的堆:

  1. ai[0,x),没用。

  2. ai[x,y),A 拿变为类型 1,B 不能拿。

  3. ai[y,2x),A,B 拿都会变为类型 1。(y2x 则不存在)

  4. ai[max(2x,y),x+y),A 拿变为类型 2,B 拿变为类型 1

然后我们进行大力分类讨论。我们定义 ti 表示第 i 种类型的堆的个数。

  • t21:A 必胜。

  • t2=0

    • t42:A 肯定可以让一个类型 4 变为类型 2,A 必胜。

    • t4=1

      • t3 为奇数:

        • A 先手:A 把类型 4 变为类型 2,A 必胜。

        • B 先手:B 只能先抢类型 4,但是接下来一人拿一堆还是必败。A 必胜。

      • t3 为偶数:先手必胜。

    • t4=0

      • t3 为奇数:先手必胜。

      • t3 为偶数:后手必胜。

记住我们只关注先手必胜和后手必胜。所以我们整理为如下:

先手必胜:t2=0t4=1t3 是偶数或 t4=0t3 是奇数。

后手必胜:t2=0t4=0t3 是偶数。

转化为数学语言:

先手必胜:ai,ai[x,y)[aimax(2x,y)]1[aiy] 为奇数。

后手必胜:ai,ai[x,y)[aimax(2x,y)]=0[aiy] 为偶数。

如果直接枚举就可以达到 O(nm2) 的复杂度,但是显然过不去。

因为我们是对 x+y 取模,所以我们可以直接枚举 x+y。令 s=x+y

然后取模之后对整个数组排序,因为 ai,ai[x,y) 等价与给 a 排序之后 x,y 都在相邻两个数之间。

再枚举 xy 出现在 aiai+1 之间。

我们发现,排序之后其实 [aiy] 我们也知道了。接下来就是解决 [aimax(2x,y)]

对于先手,[aimax(2x,y)]1,等价于 max(2x,y)>an1

max 很难搞,但是实际上,x,y 在相邻两个数之间,所以如果 y>an12x>x>an1。所以只需要计算 2x>an1

这样就可以计算出 x[l,r],其中 l=max(ai,an12)+1,r=min(s2,min(m,ai+1))s2 是因为我们一开始假设 xy

考虑把 xy 的条件去掉。这个时候其实就是 x=min(x,y),y=max(x,y),x[l,r],y[ai+1,r],l=max(ai,an12),r=min(ai+1,m)

xy 拆开,得到 xl,yl,xr,yr

最终代入 y=sx 得到答案为 x[max(l,sr),min(r,sl)]

因为一个 x 对应唯一的 y,所以 min(r,sl)max(l,sr)+1 就是枚举的 x+y 对答案的贡献。

后手同理。

最后用总方案 m2 减去先手必胜和后手必胜,再除以 2 即可得到 A 必胜与 B 必胜了。

代码实现

#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
const ll N=1e6+10;
using namespace std;

ll n,m;
ll a[N],b[N];
ll ans1,ans2;//ans1是先手必胜,ans2是后手必胜

int main(){
	
	scanf("%lld%lld",&n,&m);
	For(i,1,n)scanf("%lld",&a[i]);
	
	For(s,2,m*2){//枚举x+y
		b[n+1]=s-1;//插入一个最大值
		For(i,1,n)b[i]=a[i]%s;//取模
		sort(b+1,b+n+1);//排序
		For(i,0,n){//x,y在b[i]与b[i+1]间,注意0和n也要枚举
			ll t=(n-i)%2;//大于等于y的个数的奇偶性
			if(t==1){//计算先手必胜
				ll l=max(b[i],b[n-1]/2)+1,r=min(b[i+1],m);
				ans1+=max(0ll,min(r,s-l)-max(l,s-r)+1);
			}else{//计算后手必胜
				ll l=max(b[i],b[n]/2)+1,r=min(b[i+1],m);
				ans2+=max(0ll,min(r,s-l)-max(l,s-r)+1);
			}
		}
	}
	ll ans=(m*m-ans1-ans2)/2;//A必胜与B必胜
	printf("%lld %lld %lld %lld",ans,ans,ans1,ans2);
	
	return 0;
}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

posted @   zsc985246  阅读(240)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示