AtCoder Beginner Contest 247(D - Range Count Query)(E - K-colinear Line)
D - Range Count Query
原题链接
题面
题目大意
给你一个序列,Q次询问,每次询问区间输出 [ L , R ] [L, R] [L,R]内X有多少个。
还是喜欢写atcdoer,题目意思简洁明了
思路:
- 因为鄙人菜机刚学会莫队,看到这个问题就想用莫队来解决,但是交了两发后都
TLE
了,于是跑去看官方题解,wc好简单,这里先说题解做法。对于序列中的每一个数字x,我们可以用一个数组将其出现位置的下标存起来,放到一个vector里面,然后对于每次询问,在对应X的值里面二分找到第一个大于等于l的位置,第一个大于r的位置,作差即可。
const int N = 2e5+10;
vector<int> g[N];
void solve(){
int n; cin >> n;
for(int i = 1; i <= n; i++) {
int p; cin >> p;
g[p].push_back(i);
}
int q; cin >> q;
while(q --) {
int l, r, v; cin >> l >> r >> v;
cout << upper_bound(all(g[v]), r) - lower_bound(all(g[v]), l) << '\n';
}
}
- 莫队优化:因为不死心还是要再尝试一下莫队的优化,于是去OIWIKI翻了莫队优化,emm,优化后比上面的方法快了一倍。
const int N = 2e5+10;
int a[N], pos[N], cnt[N], ans[N];
struct A{
int l, r, v, k;
}Q[N];
void add(int p) {
cnt[a[p]] ++;
}
void sub(int p) {
cnt[a[p]] --;
}
void solve(){
int n; read(n);
int sze = sqrt(n);
for(int i = 1; i <= n; i++) {
read(a[i]);
pos[i] = i / sze;
}
int q;
read(q);
for(int i = 1; i <= q; i++) {
cin >> Q[i].l >> Q[i].r >> Q[i].v;
Q[i].k = i;
}
sort(Q + 1, Q + q + 1, [](A a, A b){
// return pos[a.l] == pos[a.r] ? a.l < b.l : pos[a.l] < pos[b.l];
return pos[a.l] == pos[b.l]
? (pos[a.r] == pos[b.r] ? 0 : ((pos[a.l]) & 1) ^ (pos[a.r] < pos[b.r]))
: pos[a.l] < pos[b.l];
});
int l = 1, r = 0;
for(int i = 1; i <= q; i++) {
while(Q[i].l < l) add(-- l);
while(Q[i].r > r) add(++ r);
while(Q[i].l > l) sub(l ++);
while(Q[i].r < r) sub(r --);
ans[Q[i].k] = cnt[Q[i].v];
}
for(int i = 1; i <= q; i++) {
print(ans[i], '\n');
}
}
oiwiki上说能快30%
hhh
E - K-colinear Line
原题链接
题面:
题目大意:
给你一个平面上N个点,问在所有任意两点构成的直线中,有多少直线上的点个数大于等于K个。
思路:
由于点数很少,可以直接暴力,时间复杂度
O
(
N
3
)
O(N^{3})
O(N3);或者先
O
(
N
2
)
O(N^{2})
O(N2)找出所有直线,用map
存一下,最后计数合法直线即可。
struct A{
int x, y;
};
void solve(){
int n, k; cin >> n >> k;
vector<A> v(n), line;
for(int i = 0; i < n; i++) cin >> v[i].x >> v[i].y;
if(k == 1) {
cout << "Infinity\n";
return ;
}
map<pair<pair<ll, ll>, ll>, int> mp;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
ll x1 = v[i].x, y1 = v[i].y, x2 = v[j].x, y2 = v[j].y;
ll a = y2 - y1, b = x1 - x2;
ll g = abs(__gcd(a, b));
a /= g;
b /= g;
ll c = -(b * y2 + a * x2);
if(a < 0) {
a = -a, b = -b, c = -c;
}
if(a == 0 && b < 0) {
b = -b, c = -c;
}
mp[{{a, b}, c}] ++;
}
}
// map中first放结构体自定义排序函数不要乱写,会有奇怪的bug
ll s = 0;
ll kk = 1ll * (k - 1) * k / 2;
for(auto& v:mp) {
if(v.second >= kk) s ++;
}
cout << s << '\n';
}