好题分享:对撞机(luogu P1871)

题面

看完题以后,想到的肯定是大模拟。但是如果裸的模拟是肯定会超时的。那我么就来想一下,裸的大模拟瓶颈在哪??

判断是否冲突。

由于判断是否冲突就是判断两数是否互质,所以我们可以自然地想到:将每个数分解因子(当然,分解质因子肯定更好,时间复杂度会更优),然后将这些因子存起来,每次新开启一个机器,就判断这个新机器的因子在已经存好的因子中是否出现过。当然,质数要特判一下

在代码实现上,肯定还会有其它的细节。具体见 c o d e code code

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 5;
int n, m;
string S[4] = {"Success", "Already on", "Already off", "Conflict with "};
bool f[maxn];//记录机器状态
set < int > s;//存所有出现过的因子
vector < int > son[maxn];//son[i]表示有哪些开启的机器包含因子i

struct my_str {
	
	inline int read() {
		int x = 0, f = 1;
		char ch = getchar();
		while(!isdigit(ch)) {
			if(ch == '-') f = -1;
			ch = getchar();
		}
		while(isdigit(ch)) {
			x = (x << 1) + (x << 3) + (ch ^ 48);
			ch = getchar();
		}
		return x * f;
	}
	
	inline int gcd(int x, int y) {
		if(x < y) swap(x, y);
		while(y) {
			int temp = x;
			x = y;
			y = temp % y;
		}
		return x;
	}
	
	void work() {
		n = read(), m = read();
		for(int i = 1; i <= m; i ++) {
			char op;
			scanf("\n%c", &op);
			if(op == '+') {
				int x = read();
				if(f[x]) {//已开启
					cout << S[1] << endl;
					continue;
				}
				bool flag = 0;
				set < int >::iterator it;
				int K = sqrt(x);
				for(int j = 2; j <= K; j ++) {//将新机器分解因子
					if(x % j == 0) {
						if(s.find(j) != s.end()) {//找到了
							cout << S[3];
							printf("%d\n", son[j][0]);//随意输出一个即可
							flag = 1;
							break;
						}
						if(x / j != j) {
							if(s.find(x / j) != s.end()) {
								cout << S[3];
								printf("%d\n", son[x / j][0]);
								flag = 1;
								break;
							}
						}
					}
				}
				if(flag) continue;
				if(s.find(x) != s.end()) {//特判素数
					cout << S[3];
					printf("%d\n", son[x][0]);
					continue;
				}
				f[x] = 1;
				cout << S[0] << endl;
				K = sqrt(x);
				flag = 0;
				for(int j = 2; j <= K; j ++) {//存入新机器的因子
					if(x % j == 0) {
						flag = 1;
						son[j].push_back(x);
						s.insert(j);
						if(x / j != j) {
							son[x / j].push_back(x);
							s.insert(x / j);
						}
					}
				}
				if(!flag) son[x].push_back(x), s.insert(x);//特判素数
			}
			else {
				int x = read();
				if(!f[x]) {//已关闭
					cout << S[2] << endl;
					continue;
				}
				f[x] = 0;
				cout << S[0] << endl;
				int K = sqrt(x);
				bool flag = 0;
				for(int j = 2; j <= K; j ++) {
					if(x % j == 0) {
						flag = 1;
						if(son[j].size() > 1) {
							vector < int >::iterator it = find(son[j].begin(), son[j].end(), x);//在vector中查找数字x
							it = son[j].erase(it);//删除函数基本用法,vector的erase函数是有返回值的,返回删除后的下一个迭代器
						}
						else son[j].clear(), s.erase(j);
						if(x / j != j && son[x / j].size() > 1) {
							vector < int >::iterator it = find(son[x / j].begin(), son[x / j].end(), x);
							it = son[x / j].erase(it);
						}
						else son[x / j].clear(), s.erase(x / j);
					}
				}
				if(!flag && son[x].size() > 1) {
					vector < int >::iterator it = find(son[x].begin(), son[x].end(), x);
					it = son[x].erase(it);
				}
				else son[x].clear(), s.erase(x);
			}
		}
	}
	
}code;

int main() {
	code.work();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值