CSP模拟8
闲话
今天老吕从国赛回来,带来一个消息:“省选可能取消,完全看 NOIP 成绩”。
不过对我没什么影响,反而还开心一些。
A. Coprime
题目大意
给定一个长度为 \(n\) 的数列 \(a\),要求出 \(1 \sim m\) 中与 \(a\) 中的所有元素互质的数。
数据范围:\(1\ \leq\ n,m\ \leq\ 10^5,1\ \leq\ a_i\ \leq\ 10^5\)。
思路
模拟赛加强了数据,卡了 \(\mathcal{O}(n \sqrt{n})\),于是来写一个 \(\mathcal{O}(n \log n)\) 的。
考虑互质是什么意思,是指两个数只有一个共同因数 \(1\)。那么如果两个数有除 \(1\) 以外的共同因数,二者不互质。
所以我们可以枚举因数,若其倍数是 \(a\) 中的元素,就可以标记我们枚举的这个因数的所有倍数都是不合法的,然后可以标记。
没标记的数都是合法的,到时候直接计数输出就行了。
苏老师想到一个 \(\mathcal{O}(n)\) 的做法,在这里,看了看感觉思路十分开阔。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N = 2005000;
int n,m;
int a[N];
bool t[N],p[N];
int pri[N],cnt;
queue<int> que;
int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i = 1;i <= n; i++) {
cin >> a[i];
p[a[i]] = 1;
}
for(int i = 2;i <= N; i++) {
bool flag = 0;
for(int j = i;j <= N; j += i) {
flag |= p[j];
}
for(int j = i;j <= N; j += i) {
t[j] |= flag;
}
}
for(int i = 1;i <= m; i++)
if(t[i] == 0) {
cnt ++;
que.push(i);
}
cout << que.size() << "\n";
while(!que.empty()) {
cout << que.front() << "\n";
que.pop();
}
return 0;
}
B.
二分答案。
一般来说找最大值的最小,最小值的最大一般都是二分答案。
我们二分的是 \(\mathrm{min}\ (\left| x_i-x_j \right|,\left| y_i-y_j \right|)\),假设现在枚举到 \(mid\),那么合法的条件是 \(\mathrm{min}\ (\left| x_i-x_j \right|,\left| y_i-y_j \right|) \geq mid\),即 \(\left| x_i - x_j \right| \geq mid\) 且 \(\left| y_i - y_j \right| \geq mid\)。
我们可以把所有点按照 \(x\) 从小到大排序,然后我们可以用双指针维护。
先定位右指针位置,使得 \(x_r - x_l \geq mid\),然后开始移动左指针,并时刻根据 \(x_r - x_l\) 的值移动右指针,这一步就保证了 \(\left| x_i - x_j \right| \geq mid\)。
两个指针位置确定时,找到左指针左侧和右指针右侧区间的的 \(y\) 的最大值、最小值,判断二者相减值是否合法。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <climits>
#include <queue>
#include <vector>
using namespace std;
const int N = 1005000;
int n;
struct Point{
int x,y;
};
bool cmp(const Point &a,const Point &b) {
return a.x < b.x;
}
vector<Point> a;
bool Check(int mid) {
int Min = INT_MAX,Max = INT_MIN;
int flag = 0;
queue<Point> que;
// 拿队列模拟指针了
for(Point t : a) {
while(!que.empty()) {
if(t.x - que.front().x < mid)
break;
Max = max(Max,que.front().y);
Min = min(Min,que.front().y);
que.pop();
}
if(Max - t.y >= mid || t.y - Min >= mid)
flag = 1;
que.push(t);
}
return flag;
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1,x,y;i <= n; i++) {
cin >> x >> y;
a.push_back((Point){x,y});
}
sort(a.begin(),a.end(),cmp);
int l = 0,r = 1e9,ans = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(Check(mid)) {
l = mid + 1;
ans = mid;
}
else
r = mid - 1;
}
cout << ans;
return 0;
}
剩下的先咕掉吧。