ZJNU - 2283 Sajam

又是一道无链接的题。

现在它是一道有链接的题啦!谢谢青烟dark在评论区指出来源!

当时在考场上画了几张图,思路是将第一行全都统一,再比较列的不同。其实有点像正解,但其实发现,我的做法无法判断第一行有变化的情况(且判断了会超时)。
下见代码。

#include<cstdio>
#include<iostream>
using namespace std;
const int N = 1002;
int n, k, G[N][N], tot1, tot2, tmp, tot;
int main() {
	char ch;
	scanf("%d %d", &n, &k);
	for(int i = 1; i <= n; i ++) {
		scanf("\n");
		for(int j = 1; j <= n; j ++) {
			ch = getchar();
			if(ch == 'x')
				G[i][j] = 1;
		}
	}
	tmp = k;
	for(int i = 1; i <= n; i ++) {
		if(G[1][i] != 0) {
			for(int j = 1; j <= n; j ++)
				G[j][i] = ! G[j][i];
		}
	}
	for(int i = 2; i <= n; i ++) {
		tot1 = tot2 = 0;
		for(int j = 1; j <= n; j ++)
			if(G[i][j] == 0)
				tot1 ++;
			else
				tot2 ++;
		tmp -= min(tot1, tot2);
		if(tmp < 0) {
			tot ++;
			break;
		}
	}
	tmp = k;
	for(int i = 1; i <= n; i ++) {
		if(G[n][i] != 0) {
			for(int j = 1; j <= n; j ++)
				G[j][i] = ! G[j][i];
		}
	}
	for(int i = 1; i < n; i ++) {
		tot1 = tot2 = 0;
		for(int j = 1; j <= n; j ++)
			if(G[i][j] == 0)
				tot1 ++;
			else
				tot2 ++;
		tmp -= min(tot1, tot2);
		if(tmp < 0) {
			tot ++;
			break;
		}
	}
	tmp = k;
	for(int i = 1; i <= n; i ++) {
		if(G[n - 1][i] != 0) {
			for(int j = 1; j <= n; j ++)
				G[j][i] = ! G[j][i];
		}
	}
	for(int i = 1; i <= n; i ++) {
		if(i == n - 1)
			continue;
		tot1 = tot2 = 0;
		for(int j = 1; j <= n; j ++)
			if(G[i][j] == 0)
				tot1 ++;
			else
				tot2 ++;
		tmp -= min(tot1, tot2);
		if(tmp < 0) {
			tot ++;
			break;
		}
	}
	if(tot == 3)
		printf("NE\n");
	else
		printf("DA\n");
	return 0;
}

然后咧,我发现了个好东西,叫异或。可以大大减低复杂度。其实我们只需再考虑一种情况:n == k。因为当相等时,所有的行都有可能被更改,之前的算法算不出来。故需要枚举一下。

上马!

#include<cstdio>
#include<bitset>
#include<iostream>
using namespace std;
const int N = 1002;
int n, k;
bitset <N> s[N];
int main() {
 int tmp, sum;
 char ch;
 scanf("%d %d", &n, &k);
 for(int i = 1; i <= n; i ++) {
  scanf("\n");
  for(int j = 1; j <= n; j ++) {
   ch = getchar();
   if(ch == 'o')
    s[i].set(j);
  }
 }
 if(n == k) {
  bool f;
  for(int i = 1; i <= n; i ++) {
   s[1].flip(i);
   f = 0;
   for(int j = 2; j <= n; j ++) {
    s[0] = s[1] ^ s[j];
    tmp = s[0].count();
    if(min(tmp, n - tmp) != 1) {//A
     f = 1;
     break;
    }
   }
   if(! f)
    return ! printf("DA\n");
   s[1].flip(i);
  }
 }
 for(int i = 1; i <= n; i ++) {
  sum = 0;
  for(int j = 1; j <= n; j ++) {
   if(j == i)
    continue;
   s[0] = s[i] ^ s[j];
   tmp = s[0].count();
   sum += min(tmp, n - tmp);
  }
  if(sum <= k)
   return ! printf("DA\n");
 }
 printf("NE\n");
 return 0;
}

注:
A:所有行修改的情况即每行改1,如有就输出DA。没有也加入后面判断,因为剩下便是至少有一行不更改。

如有错误,请大佬在评论区指出。谢谢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值