D. Tokitsukaze, CSL and Stone Game(博弈)

Problem - D - Codeforces

时津风和CSL正在玩一个石头的小游戏。

一开始,有n个石子堆,其中第ii堆有aiai石子。两位玩家轮流走棋。时津风先走。每一回合,棋手选择一个非空的棋堆,并从该棋堆中准确地取出一块石头。如果在轮到他之前,所有的棋堆都是空的,或者在取出石头之后,两个棋堆(可能是空的)包含相同数量的石头,那么玩家就输了。假设双方都以最佳状态下棋,那么谁会赢得比赛?

考虑一个例子:n=3n=3,堆的大小为a1=2a1=2,a2=3a2=3,a3=0a3=0.不可能选择空堆,所以时风有两个选择:第一和第二堆。如果她选择第一堆,那么状态将是[1,3,0][1,3,0],这是个好棋。但如果她选择第二堆,那么状态将是[2,2,0][2,2,0],她马上就输了。所以她唯一的好棋是选择第一堆。

假设两位棋手都是走自己的好棋,而且从不犯错,那么谁会赢得比赛?

请注意,即使一开始就有两堆相同数量的棋子,时风仍然可以下出有效的第一步棋。只需要在她走完后,没有两堆相同数量的棋子。

输入

第一行包含一个整数nn(1≤n≤1051≤n≤105)--棋堆的数量。

第二行包含n个整数a1,a2,...,na1,a2,...,an(0≤a1,a2,...,an≤1090≤a1,a2,...,an≤109),这意味着第ii堆有aiai的石头。

输出

如果时风会赢,则打印 "sjfnb"(不带引号);如果CSL会赢,则打印 "cslnb"(不带引号)。请注意,输出字符是区分大小写的。

例子

输入

拷贝

1
0
输出

复制

cslnb
输入

复制

2
1 0
输出

复制

cslnb
输入

复制

2
2 2
输出

复制

sjfnb
输入

复制

3
2 3 1
输出

复制

sjfnb
注意

在第一个例子中,时风不能拿任何棋子,所以CSL会赢。

在第二个例子中,时风只能从第一堆棋中取走一颗棋子,然后,尽管他们没有棋子,但这两堆棋的数量是一样的,这意味着CSL会赢。

在第三个例子中,时风将会获胜。这里有一个最佳方法:

首先,时风可以选择第一堆棋,并从这堆棋中取出一颗棋子。
然后,CSL只能选择第一堆,因为如果他选择第二堆,他将立即输掉。
最后,时风可以选择第二堆,然后CSL将别无选择,只能输。
在第四个例子中,他们在任何时候都只有一个好的选择,所以时风可以让游戏持续尽可能长的时间,最终获胜。
题解:
我们考虑如何进入到必败态

一.开始就是必败态

1.如果出现两堆为0,sjf操作不了,直接输

2.如果出现两组两堆相同的,sjf无论怎么操作肯定会有两个或以上相同,(2 2 2)这种也是(2 2 4 4)

3.如果出现i - 1,i , i这种形式,sjf无论怎么操作也会输

二.开始不是必败态,多远走到必败态

0,1,2,3......n - 1类似这样,如果一个人拿完,类似这种形式,那这个人必赢,因为下一个人无论如何怎么操作,都会出现两个相同的

排序一下,记录s += (ai - (i - 1))的值,如果%2 == 0,后手必胜,

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define int long long
typedef pair<int,int> PII; 
const int N = 1e6 + 10;
int a[100050]; 
void solve()
{
	int n;
	cin >> n;
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i];
	}
	sort(a + 1,a + 1 + n);
	int f = 0;
	for(int i = 2;i <= n;i++)
	{
		if(a[i] == a[i - 1])
		{
			f ++;
		}	
		if(a[i] == a[i - 1] &&a[i - 1]== 0)
		{
			f = 2;
		}
		if(a[i] == a[i - 1] &&i > 2&&a[i - 2] + 1 == a[i])
		{
			f = 2;
		}
	}
	int s = 0;
	for(int i = 1;i <= n;i++)
	{
		s += (a[i] - (i - 1));
	}
	if(s%2 == 0||f >= 2)
	{
		cout <<"cslnb";
	}
	else
	{
		cout <<"sjfnb";
	}
}


signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
	while(t--)
	{
		solve(); 
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值