开灯

开灯

题目描述

在一条无限长的路上,有一排无限长的路灯,编号为1,2,3,4,…。

每一盏灯只有两种可能的状态,开或者关。如果按一下某一盏灯的开关,那么这盏灯的状态将发生改变。如果原来是开,将变成关。如果原来是关,将变成开。

在刚开始的时候,所有的灯都是关的。小明每次可以进行如下的操作:

指定两个数,a,t(a为实数,t为正整数)。将编号为[a],[2 × a],[3 × a],…,[t × a]的灯的开关各按一次。其中[k]表示实数k的整数部分。

在小明进行了n次操作后,小明突然发现,这个时候只有一盏灯是开的,小明很想知道这盏灯的编号,可是这盏灯离小明太远了,小明看不清编号是多少。

幸好,小明还记得之前的n次操作。于是小明找到了你,你能帮他计算出这盏开着的灯的编号吗?

题目链接:https://www.luogu.com.cn/problem/P1161

输入格式

第一行一个正整数n,表示n次操作。

接下来有n行,每行两个数,ai, ti 。其中ai是实数,小数点后一定有6位,ti 是正整数。

输出格式

仅一个正整数,那盏开着的灯的编号。

输入输出样例

输入

3
1.618034 13
2.618034 7
1.000000 21

输出

20

题解

刚开始看到这个题的时候,第一时间想到的就是定义一个bool类型的数组vis[],刚开始所有元素初始化为false,表示灯是关着的,每次将若干盏灯改变状态,就将vis[i]变反,最后输出数值为true的那盏灯即可,但这样一来,时间复杂度就太高了,为O(m*n)。

后来换了一种思路,由于最近在尝试着使用STL的容器,就想着用set来试一下,定义:存在set中的元素i表示序号为i的灯是开着的,对于下面的n次操作,如果要将一盏灯改变状态,若它原先处于关闭的状态,即不在set容器中,那么改变状态后就处于打开的状态,就要将它插入到set中;反之,如果一盏灯原先处于打开的状态,那么改变状态之后他就是处于关闭的状态,就要从原先的set中删除,由于题目已经保证最终只有一盏灯处于打开的状态,那么就可以确认最终set中只有一个元素,输出即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	set<int>ans;
	for(int i=0;i<n;i++){
		double a;
		int t;
		cin>>a>>t;
		for(int j=1;j<=t;j++){
			if(ans.find((int)(j*a))!=ans.end()){//有这个元素 
				ans.erase((int)(j*a));
			}
			else{
				ans.insert((int)(j*a));
			} 
		}
	}
	set<int>::iterator it=ans.begin();
	cout<<(*it)<<endl;
	return 0;
}

但是这个方法需要频繁的插入和删除,最终提交的时候也是最后一个点TLE了。

这时候想起之前看到的一篇博客,可以使用异或操作,用到的性质主要有以下两条:
1.两个相同的元素异或操作后结果为0。
2.0和任何元素异或之后还是这个元素本身。
那么下面讲一下如何利用这两条性质。

所有的灯刚开始处于关闭的状态,假设一共有n盏灯,最终仍然有n-1盏灯关闭,它们状态改变的次数一定是偶数次,最终打开的那盏灯状态改变的次数一定是奇数次。因此,如果对每次给定的灯的序号进行异或操作,所有的经过偶数次改变的灯的序号的结果为0,奇数又可以等于一个偶数加一,那么最终的结果就是0异或还亮着的那盏灯的序号,输出即可。
代码如下:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int ans;
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		double a;
		int t;
		cin>>a>>t;
		for(int j=1;j<=t;j++){
			ans=ans^(int)(j*a);
		}
	}
	cout<<ans<<endl;
	return 0;
}

这个方法最终也是成功AC了,感谢各位的观看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值