NOIP模拟赛8.15----A、变换队形

A、变换队形

(transitioning.cpp/c/pas)

【问题描述】

有一个调皮的班级,他们上体育课,现在排成了n行n列的一个矩形。每个人却不是面向老师,而是面向左侧或右侧。例如:

RLR 

RRL

LLR

因为老师是新来的,所以还叫不出学生的名字。他每次都是朝着一列或一行喊:向后转。这一行或这一列的L就全部变成R,R就全部变成L。因为不能让所有学生都朝一个方向,所以体育老师退而求其次,他可以允许一个人和其他人方向相反。体育老师的指令没有次数限制,他也可以对同一行或同一列进行多次发令。请找出这样的一个学生。如果最后无法使得只有一个学生和其他人方向相反,则输出“-1”。如果存在方案,则输出那一个学生的行号和列号(均从1开始)。如果有多种方案,则输出行号最小的那一个学生,如果多个学生的行坐标相等,则输出列号最小的那一个。

【输入格式】

输入文件名为 transitioning.in。

第一行一个整数,表示n。

接下来是n行,每行n个字符,每一个字符为L或R。

【输出格式】

输出文件名为 transitioning.out。

输出文件只有 1 行,表示那个讨厌的学生的行号和列号。

如果没有,则输出-1。

【输入输出样例 】

transitioning.in

transitioning.out

3
RLR
RRL

LLR

1 1

 

 

 

【输入输出样例说明】

在这个例子中,位于第1行第1列(左上角)的学生是那个令人讨厌的学生,因为老师可以喊叫第2行和第3列向后转,只有这一个学生和其他学生朝向不同。

 

N<=1000

 

题解

先按考场上的思路讲

首先发现每一行每一列最多翻转一次

我们可以枚举一下‘那个令人讨厌的学生’的位置

把同行的与他相同的人的所在列翻转,然后把同列的与他相同的人的所在行翻转(保证了他同行同列的人都与他不同)

然后判断一下整个矩阵中他是不是与所有人不同(因为如果还需要翻转,就又会让同行同列的人不满足条件)

然后发现是O(n^4)

就开始想怎么优化

发现把每一行的状态和每一列的状态分别用bitset存起来,用位运算来快速判断翻转后的行或列是否满足条件

但仍然是O(15*n^3)

开始自闭。。。

后来自己手造了一组大样例(全屏L),然后把1000,1000换成R

结果发现秒出1000 1000

冷静分析,发现如果一个位置不是答案,基本上一次可以就把他排除掉,所以时间复杂度在O(15*n^2)左右。。。

其实后来也发现了一些性质,就是如果全图只有一个‘那个令人讨厌的学生’,那么那个位置永远也换不到其他地方(无证明)

但是不知道怎么用。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
#define N 1005
char c[N][N];
bitset<N> a[N],b[N];
int main()
{
	freopen("transitioning.in","r",stdin);
	freopen("transitioning.out","w",stdout);
	int n,i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%s",c[i]+1);
		for(j=1;j<=n;j++){
			if(c[i][j]=='L'){
				a[i].set(j);
				b[j].set(i);
			}
		}
	}
	if(n==1){
		printf("1 1");
		return 0;
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			a[i].flip(j);
			b[j].flip(i);
			int flg=0;
			for(k=1;k<=n;k++){
				if(i==k) continue;
				if(c[i][j]==c[k][j]&&(a[i]&a[k]).any()){flg=1;break;}
				if(c[i][j]!=c[k][j]&&(a[i]^a[k]).any()){flg=1;break;}
			}
			for(k=1;k<=n;k++){
				if(j==k) continue;
				if(c[i][j]==c[i][k]&&(b[j]&b[k]).any()){flg=1;break;}
				if(c[i][j]!=c[i][k]&&(b[j]^b[k]).any()){flg=1;break;}
			}
			if(!flg){
				printf("%d %d",i,j);
				return 0;
			}
			a[i].flip(j);
			b[j].flip(i);
		}
	}
	printf("-1");
}

 

正解

直接把最后一行的L位置所在列翻转(R位置也可以),

如果没有‘那个令人讨厌的学生’,则1~n-1行要么全是L,要么全是R

如果有一个,则他就会在那一行显得尤为突出(在那一行与众不同)

记一下突出学生的个数(>1就输出-1)与第一个突出学生的位置,就是答案了

如果突出学生的个数=n-1的话,且都在同一列,就说明‘那个令人讨厌的学生’在最后一行的该列。

(以上是我个人理解,std的实现可能略有不同)(好像std有点问题)

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
int n;
char s[MAXN][MAXN];
int cnt[MAXN];
int ansx,ansy,cntR;
int cntx,miny1,miny2;
int main()
{
    freopen("transitioning.in","r",stdin);
    freopen("transitioning.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%s",s[i]+1);
    for(int j=1;j<=n;j++)
    {
      if(s[n][j]=='R')
      cnt[j]^=1;
    }
    for(int i=n-1;i>=1;i--)
    {
        cntR=0;
        for(int j=n;j>=1;j--)
           if(s[i][j]=='R'&&cnt[j]==0||s[i][j]=='L'&&cnt[j]==1)
            cntR++,miny1=j;
           else
           miny2=j;
           if(cntR==0||cntR==n)
           {
             continue;
           }
           else
           {
             if(min(n-cntR,cntR)==1)
             {
               if(cntx>0)
               {
               printf("-1\n");
               return 0;
               }
               else
               {ansx=i;
                if(cntR==1)ansy=miny1;
                else ansy=miny2;
               cntx++;
               }
             }
             else
             {
                printf("-1\n");
                return 0;
             }
           }
    }
    if(ansx==0&&ansy==0)
    printf("-1\n");
    else
    printf("%d %d\n",ansx,ansy);
    return 0;
}

感想

遇到01矩阵翻转问题还是要冷静分析,抓住每一个可操作点最多只操作一次,再分析一下有关性质就可以了

总之,思路要灵活,实在不行就写暴力。。。

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个参选手有相同的机会和条件进行竞争。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值