C++解题报告:Tokitsukaze, CSL and Stone Game[ COCI ] —— 博弈论

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_44013342/article/details/99685608

题目描述

Irressey与yurzhang在玩一个取石子的游戏

一开始,他们面前有nn堆石子,第ii堆石子有a_iai​颗石头,他们轮流取石子(Irressey先取)。每一次,取石子的人会选中一个非空的石子堆并取走其中的一颗石子。如果在某个人的回合前所有的石子堆都是空的,或者在他取完后有两堆的石子数量相同(两堆都没有石子也算),则他输掉游戏。

如果lrressey胜利,输出sjfnb;如果yurzhang胜利,输出cslnb(假设两个人都按最好的策略去取)

数据范围:

1≤n≤10^5

0≤a1​,a2​,a3​...an​≤10^9

输入输出样例

输入 #1复制

1
0

输出 #1复制

cslnb

输入 #2复制

2
1 0

输出 #2复制

cslnb

输入 #3复制

2
2 2

输出 #3复制

sjfnb

输入 #4复制

3
2 3 1

输出 #4复制

sjfnb

思路详解

首先我们考虑一下一上来,先手(rp原地爆炸)直接输的情况

用 L[ i ] 存有 i 个石头的堆的个数

1. L[ i ] >= 3,有3个相等堆,取了一个,另外两个依然相等

2. L[ x ] >= 2 并且 L[ y ] >= 2 ,有两种不同相等堆

3. L[ i ] >= 2 并且 L[ i-1 ] >= 1,取了一个相等堆,变为 i-1,而 L[ i-1 ] 加 1,又产生相等堆

4. L[ 0 ] >= 2 堆为 0,不能取

这种情况,先手直接被秒。。。

然后我们知道要让石堆不相等,只能让石堆为 0,1,2,3,4......n-1 (自己理解一下)

用 sum 统计石堆和,减去 (n-1)*n/2,剩下的如果为奇数,先手获胜;为偶数,后手获胜

如果 sum <= (n-1)*n/2 ,后手胜,因为石堆必定无法形成 0,1,2......n-1的数列

 


代码

博弈论都是毒瘤的思维题,看思路,理解消化。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <algorithm>
#define ll long long
#define N 200005
using namespace std;

int n , cnt ;
ll sum , a[N] , cum ;
map <int,int> L ;
bool flag , vis1 ;

int main() {
	scanf("%d", &n );
	for( int i = 1 ; i <= n ; ++ i )
		scanf("%lld", &a[i] );
	sort( a+1 , a+n+1 );
	for( int i = 1 ; i <= n ; ++ i ) {
		sum += a[i] ;
		L[a[i]] ++ ;
		if( L[a[i]] > 2 )//两个以上相等堆 
			flag = 1 ;
		if( L[a[i]] == 2 && L[a[i]-1] == 1 )//一个相等堆且该堆减 1 的堆有至少一个 
			flag = 1 ;
		if( L[a[i]] == 2 && vis1 )
			flag = 1 ;
		if( L[a[i]] == 2 )
			vis1 = 1 ;
		if( L[a[i]] == 2 && a[i] == 0 )
			flag = 1 ;
	}
	if( n == 2 && vis1 && a[1] == 0 ) {
		printf("cslnb");
		return 0 ;
	}
	if( flag ) {
		printf("cslnb");
		return 0 ;
	}
	cum = (n-1)*n/2 ;
	if( sum-cum <= 0 ) {
		printf("cslnb");
		return 0 ;
	}
	if( (sum-cum)%2 == 0 )
		printf("cslnb");
	else printf("sjfnb");
}

猜你喜欢

转载自blog.csdn.net/qq_44013342/article/details/99685608