AtCoder Beginner Contest 248 D - Range Count Query E - K-colinear Line

本文介绍了AtCoderBeginnerContest247的D题RangeCountQuery和E题K-colinearLine的解题思路。D题使用莫队算法优化解决区间查询问题,E题则通过暴力或预处理方法解决平面上点的共线问题。
摘要由CSDN通过智能技术生成

AtCoder Beginner Contest 247(D - Range Count Query)(E - K-colinear Line)

D - Range Count Query

原题链接

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

原题链接

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';
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值