隔膜

隔膜

题面

小 l 和小 c 在玩游戏。
她们发明了一个新的游戏。
有一个 n × n 的棋盘,初始有些地方有棋子。
每次行动时,需要在棋盘上找到一个 k × k 的正方形,使得上面没有任何一个棋子。如果无法找
到,则她就输掉了这个游戏。
然后,她需要在棋盘任. 意. 一. 个. 没有棋子的地方放上一个棋子,不需要保证这个棋子在 k × k 的正方形中。
小 c 先手,问谁有必胜策略。

输入格式

从文件 lcyrcx.in 中读入数据。
第一行包含两个正整数 n, k。
接下来 n 行,每行输入一个长度为 n 的 0/1 字符串,1 表示上面初始有棋子,0 表示上面初始
没有棋子。

输出格式

输出到文件 lcyrcx.out 中。
输出一行一个字符串,表示谁赢了。如果小 l 赢了,输出 yc,否则输出 rx。

题解

讨论3种情况:
1.一开始棋盘上找不到正方形。此时答案即为小l赢了
2.一开始棋盘找得到正方形且上存在一个点,使得在这个点放了一个棋子后棋盘上找不到正方形,此时小c先手放在这个位置,小l就找不到位置放了,此时答案即为小c赢了。
3.除去1,2种情况即为3情况,此时图上一定能找到至少2个互不相交的正方形。当只剩2个互不相交的正方形时,谁先往其中一个正方形里放棋子,谁就输了。所以此时最优决策就是把不在互不相交正方形内的空位置全都放满。然后放完之后必须放在正方形内的那个人就输了。
若存在3个及以上个互不相交的正方形,可以证明,先放正方形内和先放正方形外的空位置到最后只剩下2个互不相交的正方形时的人是一样的。证明:若先放正方形内,能找到的正方形便减1,而此时若只剩2个,便不能再放正方形内。若先放正方形外,到最后就会剩下一堆互不相交的正方形,然后又回到了上面的情况。
所以,情况3的答案ans=空格子的总数-2kk,若ans为奇数,则小c赢了,否则小l赢了。

代码如下

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int k=0,f=1;char ch;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')k=k*10+ch-'0',ch=getchar();
	return k*f;
}
const int N=1e3+5;
int n,k,a[N][N];
void point1(){
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			if(a[i][j]){printf("yc\n");return;}
	printf("rx\n");
}
int hang[N][N],lie[N][N],f[N][N],s[N][N],cnt_,sum;
bool solve(){
	for(int i=1;i<=n;++i){
		for(int j=1,cnt=0;j<=n;++j){
			if(j>k&&a[i][j-k])cnt--;
			if(a[i][j])cnt++;
			if(j>=k)hang[i][j-k+1]=cnt;//,cout<<i<<" "<<j-k+1<<" "<<cnt<<endl;
		}
		/*for(int j=1,cnt=0;j<=n;++j){
			if(j>k&&a[j-k][i])cnt--;
			if(a[j][i])cnt++;
			if(j>=k)lie[j-k+1][i]=cnt;
		}*/
	}
	for(int i=1;i+k-1<=n;++i){
		for(int j=1,cnt=0;j<=n;++j){
			if(j>k)cnt-=hang[j-k][i];
			cnt+=hang[j][i];
			if(j>=k&&!cnt){
				f[j+1][i]--;
				f[j-k+1][i]++;
				f[j-k+1][i+k]--;
				f[j+1][i+k]++;
				cnt_++;
			}
		}
	}
	
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+f[i][j];//,cout<<i<<" "<<j<<" "<<s[i][j]<<endl;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){
			if(s[i][j]==cnt_)return false;
		}
	return true;
}
int main()
{
	char ch;
//	freopen("lcyrcx.in","r",stdin);
//	freopen("lcyrcx.out","w",stdout);
	n=read(),k=read();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			cin>>ch,a[i][j]=ch-'0',sum+=(a[i][j]^1);
	//cout<<sum<<endl;
	if(solve()){
	//	cout<<"FAQ "<<cnt_<<endl;
		if((sum-2*k*k)%2)printf("rx\n");
		else printf("yc\n");
	}
	else{
		
		if(cnt_==0)printf("yc\n");
		else printf("rx\n");
	}
	return 0;
}
/*
4 2
0001
0000
1100
1111
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值