0815模拟赛

1.变换队形
【问题描述】
有一个调皮的班级,他们上体育课,现在排成了n行n列的一个矩形。每个人却不是面向老师,而是面向左侧或右侧。例如:
RLR
RRL
LLR
因为老师是新来的,所以还叫不出学生的名字。他每次都是朝着一列或一行喊:向后转。这一行或这一列的L就全部变成R,R就全部变成L。因为不能让所有学生都朝一个方向,所以体育老师退而求其次,他可以允许一个人和其他人方向相反。体育老师的指令没有次数限制,他也可以对同一行或同一列进行多次发令。请找出这样的一个学生。如果最后无法使得只有一个学生和其他人方向相反,则输出“ − 1 -1 1”。如果存在方案,则输出那一个学生的行号和列号(均从1开始)。如果有多种方案,则输出行号最小的那一个学生,如果多个学生的行坐标相等,则输出列号最小的那一个。

n &lt; = 1000 n&lt;=1000 n<=1000

假设特别学生不在最后一排,那么最后一排就能确定每一列是否被翻转。
然后对于前面的每一排就只能整排翻转,分类讨论即可。
如果在最后一排,那么就不在第一排,再来一遍即可。

因为想的时间比较长所以写的时候就没怎么看题面导致最后自以为是的输出了两个 − 1 -1 1
看题目,做前做后做时都要根据题目而不要被自己的分析过度干涉,写题要扣题。。。。

AC Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 1005
using namespace std;

int n;
char s[maxn];
int mp[maxn][maxn],bmp[maxn][maxn];
pair<int,int>ans;

void rline(int x){
	for(int i=1;i<=n;i++)
		mp[i][x] ^= 1;
}

void rco(int x){
	for(int i=1;i<=n;i++)
		mp[x][i] ^= 1;
}

void Solve(){
	int cnt = 0;
	for(int i=1;i<=n;i++){
		int s1 = 0 , s2 = 0;
		for(int j=1;j<=n;j++)
			if(mp[i][j])
				s1++;
			else 
				s2++;
		if(s2 < s1) rco(i);
		cnt+=min(s1,s2);
	}
	
	if(cnt == 1){
		for(int i=1;i<=n;i++){
			int s = 0; 
			for(int j=1;j<=n;j++)
				if(mp[i][j] == 1)
					ans = min(ans , make_pair(i,j)) , s++;
			if(s){
				rco(i);
				s = 0;
				for(int j=1;j<=n;j++)
					if(mp[i][j]) s++;
				if(s ==1){
					for(int j=1;j<=n;j++)
						if(mp[i][j]) 
							ans = min(ans , make_pair(i,j));
				}
			}
		} 
	}
	
	if(cnt == 0){
		for(int i=1;i<=n;i++){
			rco(i);
			int s = 0;
			for(int j=1;j<=n;j++)
				if(mp[i][j]) s++;
			if(s == 1)
				for(int j=1;j<=n;j++)
					if(mp[i][j])
						ans = min(ans , make_pair(i,j));
		}
	}
}

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+1);
		for(int j=1;j<=n;j++)
			mp[i][j] = (s[j] == 'L');
	}
	memcpy(bmp,mp,sizeof mp);
	
	ans = make_pair(0x3f3f3f3f,0x3f3f3f3f);
	
	for(int i=1;i<=n;i++)
		if(mp[n][i])
			rline(i);
	Solve();
	memcpy(mp,bmp,sizeof bmp);
	for(int i=1;i<=n;i++)
		if(mp[1][i])
			rline(i);
	Solve();
	
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			bmp[i][j] ^= 1;
	memcpy(mp,bmp,sizeof bmp);
	for(int i=1;i<=n;i++)
		if(mp[n][i])
			rline(i);
	Solve();
	memcpy(mp,bmp,sizeof bmp);
	for(int i=1;i<=n;i++)
		if(mp[1][i])
			rline(i);
	Solve();
	
	if(ans.first >= 0x3f3f3f3f)
		puts("-1");
	else 
		printf("%d %d\n",ans.first,ans.second);
}
  1. 跨栏
    【问题描述】
    在过去,校长曾经构思了许多新式学生运动项目的点子,其中就包括学生障碍赛,是学生们在赛道上跑越障碍栏架的竞速项目。他之前对推广这项运动做出的努力结果喜忧参半,所以他希望在他的操场上建造一个更大的学生障碍赛的场地,试着让这项运动更加普及。校长为新场地精心设计了N个障碍栏架,编号为 1 … N 1…N 1N 2 ≤ N ≤ 1 0 5 2≤N≤10^5 2N105),每一个栏架都可以用这一场地的二维地图中的一条线段来表示。这些线段本应两两不相交,包括端点位置。
    不幸的是,校长在绘制场地地图的时候不够仔细,现在发现线段之间出现了交点。然而,他同时注意到只要移除一条线段,这张地图就可以恢复到预期没有相交线段的状态(包括端点位置)。
    请求出校长为了恢复没有线段相交这一属性所需要从他的计划中删去的一条线段。如果有多条线段移除后均可满足条件,请输出在输入中出现最早的线段的序号。
    【输入格式】
    输入的第一行包含N。余下N行每行用四个整数x1 y1 x2 y2表示一条线段,均为至多109的非负整数。这条线段的端点为(x1,y1)和(x2,y2)
    。所有线段的端点各不相同。
    【输出格式】
    输出在输入中出现最早的移除之后可以使得余下线段各不相交的线段序号。

扫描线套set,可以膜一下平面图点定位。

AC Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#define eps 1e-8
#define maxn 100005
using namespace std;

int n;
int sgn(const double &a){  
	return a < -eps ? -1 : a > eps ? 1 : 0;
}

struct Point{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
	Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
	double operator *(const Point &B)const{ return x*B.y-y*B.x; }
}A,B;

double nowx;
struct Line{
	Point A,B;
	double k;
	int id;
	bool operator <(const Line &B)const{
		double u = A.y + k * (nowx - A.x) , v = B.A.y + B.k * (nowx - B.A.x);
		if(sgn(u-v)) return u < v;
		return id < B.id;
	}
}L[maxn];
int L1, L2;


set<Line>st;

struct opt{
	int id,op;
	double x;
	bool operator <(const opt&B)const{
		if(sgn(x - B.x)) return x < B.x;
		return op < B.op; 
	}
}Q[maxn * 2];

bool check(const Line &u,const Line &v){
	return ((v.B-v.A)*(u.A-v.A)) * ((v.B-v.A)*(u.B-v.A)) <= 0 && 
		   ((u.B-u.A)*(v.A-u.A)) * ((u.B-u.A)*(v.B-u.A)) <= 0;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y);
		if(A.x > B.x) swap(A,B);
		if(sgn(B.x - A.x))
			L[i].k = (B.y - A.y) / (B.x - A.x);
		else 
			L[i].k = 0;
		L[i].A=A,L[i].id = i,L[i].B=B;
		Q[i*2-1].id = i , Q[i*2-1].op = 0 , Q[i*2-1].x = A.x;
		Q[i*2  ].id = i , Q[i*2  ].op = 1 , Q[i*2  ].x = B.x;
	}
	
	sort(Q+1,Q+1+2*n);
	for(int i=1;i<=2*n;i++){
		nowx = Q[i].x;
		if(Q[i].op == 0){
			set<Line>::iterator it = st.lower_bound(L[Q[i].id]);
			if(it != st.end()){
				if(check((*it),L[Q[i].id])){
					L1 = (*it).id , L2 = Q[i].id;
					break;
				}
			}
			if(it!=st.begin()){
				it--;
				if(check(*it,L[Q[i].id])){
					L1 = (*it).id , L2 = Q[i].id;
					break;
				}
			}
			st.insert(L[Q[i].id]);
		}
		else{
			st.erase(L[Q[i].id]);
			set<Line>::iterator it = st.lower_bound(L[Q[i].id]);
			if(it!=st.end() && it!=st.begin()){
				set<Line>::iterator it2 = it;it2--;
				if(check(*it,*it2)){
					L1 = (*it).id , L2 = (*it2).id;
					break;
				}	
			}
		}
	}
	int cL1 = 0 , cL2 = 0;
	for(int i=1;i<=n;i++)
		if(i!=L1 && i!=L2){
			if(check(L[i],L[L1])) cL1++;
			if(check(L[i],L[L2])) cL2++;
		}
	int ans = 0x3f3f3f3f;
	if(!cL1 && !cL2) ans = min(L1,L2);
	else if(!cL1) ans = L2;
	else ans = L1;
	printf("%d\n",ans);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值