题目描述
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");
}