无锡学院第一届程序设计竞赛&GPLT选拔赛

链接: https://ac.nowcoder.com/acm/contest/77760

\(\\\)

A 美丽字符串
从左起遍历,记长度为 \(i\) 的子串的出现次数为 \(S[i]\),那么任意长度为 \(j\) 的连续子串,其贡献是 \(1\),对于所有的 \(S[k],k∈[1,j]\) 。容易想到用线段树来统计贡献。复杂度 \(O(n logn)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

class Z {
    using i64 = long long;
    static const i64 Mod = 1000000007;
public:
    i64 num;
    Z() = default;
    Z(i64 _num) : num((_num % Mod + Mod) % Mod) {}
    i64 val() const {
        return num;
    }
    Z &operator = (i64 b) {
        return *this = Z(b);
    }
    friend bool operator < (Z a, Z b) {
        return a.num < b.num;
    }
    friend bool operator >(Z a, Z b) {
        return a.num > b.num;
    }
    friend bool operator <=(Z a, Z b) {
        return a.num <= b.num;
    }
    friend bool operator>=(Z a, Z b) {
        return a.num >= b.num;
    }
    friend bool operator==(Z a, Z b) {
        return a.num == b.num;
    }
    friend Z operator + (Z a, Z b) {
        return Z((a.num + b.num) % Mod);
    }
    friend Z &operator += (Z &a,Z b) {
        return a = a + b;
    }
    friend Z operator + (Z a, i64 b) {
        return a + Z(b);
    }
    friend Z &operator += (Z &a, i64 b) {
        return a = a + b;
    }
    friend Z &operator ++ (Z &a) {
        return a += 1;
    }
    friend Z operator ++ (Z &a, int) {
        Z copy(a);
        a += 1;
        return copy;
    }
    friend Z operator - (Z a, Z b) {
        return Z(((a.num - b.num) % Mod + Mod) % Mod);
    }
    friend Z &operator -= (Z &a, Z b) {
        return a = a - b;
    }
    friend Z operator - (Z a, i64 b) {
        return a - Z(b);
    }
    friend Z &operator -= (Z &a, i64 b) {
        return a = a - b;
    }
    friend Z &operator -- (Z &a) {
        return a -= 1;
    }
    friend Z operator -- (Z &a, int) {
        Z copy(a);
        a -= 1;
        return copy;
    }
    friend Z operator * (Z a, Z b) {
        return Z((long long)a.num * b.num % Mod);
    }
    friend Z &operator *= (Z &a, Z b) {
        return a = a * b;
    }
    friend Z operator * (Z a, i64 b) {
        return a * Z(b);
    }
    friend Z &operator *= (Z &a, i64 b) {
        return a = a * b;
    }
    Z inv() {
        i64 ans = 1;
        i64 a = num;
        i64 b = Mod - 2; 
        while (b) {
            if (b & 1) ans = ans * a % Mod;
            a = a * a % Mod;
            b >>= 1;
        }
        return Z(ans);
    }
    friend Z operator / (Z a, Z b) {
        return a * b.inv();
    }
    friend Z &operator /= (Z &a, Z b) {
        return a = a / b;
    }
    friend Z operator / (Z a, i64 b) {
        return a / Z(b);
    }
    friend Z &operator /= (Z &a, i64 b) {
        return a = a / b;
    }
    friend std::istream &operator>>(std::istream &is, Z &a) {
        int v;
        is >> v;
        a = Z(v);
        return is;
    }
    friend std::ostream &operator<<(std::ostream &os, const Z &a) {
        return os << a.val();
    }
};

template<class Info, class Tag>
struct LazySegmentTree {
    const int n;
    std::vector<Info> info;
    std::vector<Tag> tag;
    LazySegmentTree(int n) : n(n), info(4 << std::__lg(n)), tag(4 << std::__lg(n)) {}
    LazySegmentTree(std::vector<Info> init) : LazySegmentTree(init.size()) {
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void apply(int p, const Tag &v) {
        info[p].apply(v);
        tag[p].apply(v);
    }
    void push(int p) {
        apply(2 * p, tag[p]);
        apply(2 * p + 1, tag[p]);
        tag[p] = Tag();
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        push(p);
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        push(p);
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
    void rangeApply(int p, int l, int r, int x, int y, const Tag &v) {
        if (l >= y || r <= x) {
            return;
        }
        if (l >= x && r <= y) {
            apply(p, v);
            return;
        }
        int m = (l + r) / 2;
        push(p);
        rangeApply(2 * p, l, m, x, y, v);
        rangeApply(2 * p + 1, m, r, x, y, v);
        pull(p);
    }
    void rangeApply(int l, int r, const Tag &v) {
        return rangeApply(1, 0, n, l, r, v);
    }
    void half(int p, int l, int r) {
        if (info[p].act == 0) {
            return;
        }
        if ((info[p].min + 1) / 2 == (info[p].max + 1) / 2) {
            apply(p, {-(info[p].min + 1) / 2});
            return;
        }
        int m = (l + r) / 2;
        push(p);
        half(2 * p, l, m);
        half(2 * p + 1, m, r);
        pull(p);
    }
    void half() {
        half(1, 0, n);
    }
};

struct Tag {
    i64 add = 0;
    void apply(Tag t) {
        add += t.add;
    }
};

struct Info {
    i64 Act = 1;
    i64 Sum = 0;
    void apply(Tag t) {
        Sum += Act * t.add;
    }
};

Info operator+(Info a, Info b) {
    Info c;
    c.Sum = a.Sum + b.Sum;
    c.Act = a.Act + b.Act;
    return c;
}

i64 power(i64 a, i64 b) {
    const i64 Mod = 1000000007; 
    i64 res = 1;
    i64 base = a;
    while (b) {
        if (b & 1) {
            res = res * base % Mod;
        }
        base = base * base % Mod;
        b >>= 1;
    }
    return res;
}

void solve() {
    cin >> n;
    string s;
    cin >> s;

    LazySegmentTree<Info, Tag> seg(n + 5);

    for (int i = 0; i < s.size(); i++) {
        if (i == s.size() - 1) {
            seg.rangeApply(1, 2, Tag{1});
            break;
        }
        for (int j = i; j < s.size(); j++) {
            if (j == i || s[j] == s[j - 1] + 1) {
                seg.rangeApply(1, j - i + 2, Tag{1});
                if (j == s.size() - 1) {
                    i = j;
                    break;
                }
            } else {
                i = j - 1;
                break;
            }
        }
    }

    Z ans = 0;

    for (int i = 1; i <= n; i++) {
        i64 pw = seg.rangeQuery(i, i + 1).Sum;
        ans += pw * power(2, i);
    }

    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

B 帕鲁对对碰
每次伤害为 \(2^i\),最少的攻击次数显然为血量二进制中 \(1\) 的个数,可以用 __\(builtin\)_$ \ popcount()$ 方法计算。复杂度小于 \(O(logn)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

void solve() {
    cin >> n >> m;

    int x = __builtin_popcount(n);
    int y = __builtin_popcount(m);

    cout << (y <= x ? "Alice" : "Bob") << " " << min(x, y) << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

C 植树青年
考虑二分答案,对于当前的天数 \(x\), 需要的骨灰数量为 \(\displaystyle\sum_{i=1}^n max(a[i] - x, 0)\),这一部分可以 \(O(n)\) 计算,复杂度 \(O(n logn)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

void solve() {
    cin >> n >> m;

    vector<i64> p(n);
    for (int i = 0; i < n; i++) {
        cin >> p[i];
    }

    auto check= [&](i64 u) -> bool {
        i64 cur = 0;
        for (auto c: p) {
            if (c > u) {
                cur += c - u;
            }
        }
        return cur <= m;
    };

    i64 l = 0, r = 1e9;
    while (l <= r) {
        i64 mid = l + r >> 1;
        if (check(mid)) {
            r = mid - 1;
        } else {
            l = mid + 1;
        }
    }

    cout << l << endl;
 
}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

D 单词典
暴力枚举即可。复杂度 \(O(nm)\)\(n,m\) 为字符串的长度。

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

void solve() {
    string a, b;
    cin >> a >> b;

    int ans = 0;

    for (int i = 0; i < a.size(); i++) {
        ans += a.substr(i, b.size()) == b;
    }

    cout << ans << endl;
 
}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

E 胡萝卜(easy)
给定的所有胡萝卜重量都大于 \(0\),即每次捡胡萝卜对答案的贡献都是正的,所以全部选择即可。最大和最小的胡萝卜可以用 \(multiset\) 维护,复杂度 \(O(n logn)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

void solve() {
    cin >> n >> m;

    vector<i64> p(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
    }

    vector<i64> q(n + 1);
    while (m--) {
        cin >> k;
        q[abs(k)] = k;
    }

    multiset<i64> st;

    for (int i = 1; i <= n; i++) {
        if (q[i] > 0 && st.size()) {
            st.extract(*st.rbegin());
        }
        if (q[i] < 0 && st.size()) {
            st.extract(*st.begin());
        }
        st.insert(p[i]);
    }

    i64 ans = 0;
    for (auto c: st) {
        ans += c;
    }

    cout << ans << endl;
 
}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

F MHWI
统计四条线段和给定的所有线段的相交情况,给定线段的单个贡献至多为 \(1\),考虑用矢量叉积计算,若两线段相交,当且仅当下面条件至少存在一个,
\(1.\) 线段都跨越了包含另一条线段的直线。
\(2.\) 一条线段的一个端点落在另一条线段上。
注意标记单个线段的贡献情况。复杂度 \(O(n)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

int sgn(i64 x) { return x < 0 ? -1 : x > 0; }

struct Point {
    i64 x, y;
    Point(i64 x = 0, i64 y = 0) : x(x), y(y) {}
    Point operator- (const Point &B) const { return Point(x - B.x, y - B.y); }
    Point operator+ (const Point &B) const { return Point(x + B.x, y + B.y); }
    i64 operator^ (const Point &B) const { return x * B.y - y * B.x; }
    i64 operator* (const Point &B) const { return x * B.x + y * B.y; }
};

int Cross(Point a, Point b, Point c) { return sgn((b - a) ^ (c - a)); }

bool OnSegment(Point P, Point A, Point B) {
    Point PA = A - P, PB = B - P;
    return sgn(PA ^ PB) == 0 && sgn(PA * PB) <= 0;  
}

bool Intersect(Point a, Point b, Point c, Point d) {
    if (OnSegment(a, c, d) || OnSegment(b, c, d) || OnSegment(c, a, b) || OnSegment(d, a, b)) return 1;
    if (Cross(a, b, c) * Cross(a, b, d) >= 0) return 0;
    if (Cross(c, d, a) * Cross(c, d, b) >= 0) return 0;
    return 1;
}

void solve() {
    i64 d;
    cin >> n >> d;

    int ans = 0;
    vector<bool> vis(n);

    vector<pair<Point, Point>> p(n);
    for (int i = 0; i < n; i++) {
        cin >> p[i].first.x >> p[i].first.y >> p[i].second.x >> p[i].second.y;
    }

    Point O(0, 0), A(0, d), B(0, -d), C(d, 0), D(-d, 0);

    for (int i = 0; i < n; i++) {
        auto check = Intersect(O, A, p[i].first, p[i].second);
        if (check && !vis[i]) {
            ans += check;
            vis[i] = true;
        }
    }

    for (int i = 0; i < n; i++) {
        auto check = Intersect(O, B, p[i].first, p[i].second);
        if (check && !vis[i]) {
            ans += check;
            vis[i] = true;
        }
    }

    for (int i = 0; i < n; i++) {
        auto check = Intersect(O, C, p[i].first, p[i].second);
        if (check && !vis[i]) {
            ans += check;
            vis[i] = true;
        }
    }

    for (int i = 0; i < n; i++) {
        auto check = Intersect(O, D, p[i].first, p[i].second);
        if (check && !vis[i]) {
            ans += check;
            vis[i] = true;
        }
    }

    if (!ans) {
        cout << "No" << endl;
        return ;
    }

    cout << "Yes" << endl;
    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}

\(\\\)

G 排列再现
贪心,升序排序之后按 \(a[i] = i\) 计算贡献。一种简易猜想方法是考虑序列 \({\{a[1],a[2],……,a[n]\}}\) 为非降序序列,此时的答案为 \(\sum_{i=1}^n \mid a[i]-i \ \mid\),任意交换一对元素 \(( \ a[x], \ a[y], \ 0 \leqslant x<y \leqslant 1)\),相比于非降序序列所减小的计算量为 \(I=( \mid a[x]-x\mid + \mid a[y]-y \mid) - ( \mid a[x]-y\mid + \mid a[y]-x \mid)\),考虑证明 \(I<0\),移项后平方,即证明\((\mid a[x]-x \mid + \mid a[y]-y \mid)^2 < (\mid a[x]-y\mid + \mid a[y] - x \mid)^2\),根据 \(wolfram \ alpha\),它是对的。

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

void solve() {
    cin >> n;

    vector<i64> p(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
    }

    sort(p.begin() + 1, p.end());

    i64 ans = 0;

    for (int i = 1; i <= n; i++) {
        ans += abs(i - p[i]);
    }

    cout << ans << endl;
 
}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}  

\(\\\)

H 如听仙乐耳暂明
对每首歌的时长取模后用 \(map\) 记录数量,逐一求解即可。复杂度\(O(max(nlogn,30logn))\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

void solve() {
    cin >> n;

    vector<i64> p(n);
    map<i64, i64> mp;
    for (int i = 0; i < n; i++) {
        cin >> p[i];
        p[i] %= 60;
        mp[p[i]]++;
    }

    int ans = 0;

    for (auto &[x, y]: mp) {
        if (x > 30) {
            break;
        }

        if (x == 30) {
            ans += y / 2 * 2;

        } else if (x) {
            if (mp.find(60 - x) != mp.end()) {
                int u = min(y, mp[60 - x]);
                ans += 2 * u;
            }

        } else {
            ans += y;
        }
    } 

    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
} 

\(\\\)

I 胡萝卜(hard)
和 easy 版本的做法一样,在最后计算答案时,去掉所有负数重量的胡萝卜即可。复杂度 \(O(nlogn)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

void solve() {
    cin >> n >> m;

    vector<i64> p(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
    }

    vector<i64> q(n + 1);
    while (m--) {
        cin >> k;
        q[abs(k)] = k;
    }

    multiset<i64> st;

    for (int i = 1; i <= n; i++) {
        if (q[i] > 0 && st.size()) {
            st.extract(*st.rbegin());
        }
        if (q[i] < 0 && st.size()) {
            st.extract(*st.begin());
        }
        st.insert(p[i]);
    }

    i64 ans = 0;
    for (auto c: st) {
        if (c < 0) {
            continue;
        }
        ans += c;
    }

    cout << ans << endl;
 
}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

J 计算机网络
对于两点之间是否连通,可以用并查集维护,或者不做也可以。对于答案的求解,考虑 \(BFS\) ,用 \(map\) 记录每个点的状态做剪枝。复杂度不会算,大约是 \(O(nlog^2n)\) 量级的。

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

struct g {
    i64 v;
    i64 u;
    g(i64 u_, i64 v_): v(v_), u(u_) {}
};

struct DSU {
    using i64 = long long;
    vector<i64> fa, siz;
    DSU(i64 n) : fa(n + 1), siz(n + 1, 1) { iota(fa.begin(), fa.end(), 0); };
    i64 find(i64 x) {
        while (x != fa[x]) x = fa[x] = fa[fa[x]];
        return x;
    }
    i64 size(i64 x) { return siz[find(x)]; }
    i64 len() {
        i64 ans = 0;
        for (int i = 1; i <= n; i++) {
            if(find(i) == i) ans++;
        }
        return ans;
    }
    bool same(i64 x, i64 y) { return find(x) == find(y); }
    bool merge(i64 x, i64 y) {
        x = find(x), y = find(y);
        if (x == y) return false;
        siz[y] += siz[x];
        fa[x] = y;
        return true;
    }
};

constexpr int N = 1e5 + 5;

void solve() {
    int s, t;
    cin >> n >> m >> s >> t;

    DSU dsu(N);

    vector<i64> vis(n + 1, 1e18);
    map<pair<int, int>, i64> dis;
    vector<vector<int>> adj(n + 1);
    vector<i64> p(n + 1);

    for (int i = 1; i <= n; i++) {
        cin >> p[i];
    }

    i64 x, y, z;
    while (m--) {
        cin >> x >> y >> z;
        dis[{x, y}] = dis[{y, x}] = z;
        adj[x].emplace_back(y);
        adj[y].emplace_back(x);
        dsu.merge(x, y);
    }

    if (!dsu.same(s, t)) {
        cout << -1 << endl;
        return ;
    }
    
    i64 ans = 1e18;

    auto bfs = [&]() -> void {
        queue<g> q;
        g st(s, 0);
        q.push(st);
        vis[s] = 0;
        
        while (!q.empty()) {
            auto c = q.front();
            q.pop();
            if (c.u == t) {
                ans = min(ans, c.v);
            }
            for (auto d: adj[c.u]) {
                g nxt(d, c.v + p[c.u] + dis[{c.u, d}]);
                if (nxt.v < vis[d]) {
                    q.push(nxt);
                    vis[d] = nxt.v;
                }
            }
        }
    };

    bfs();

    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

K Boom
传统扫描线的做法会出现精度问题,观察此题 \(n\) 的范围非常小,用 \(DFS\) 维护当前点集,直接打个裸的暴力即可。复杂度 \(O(n^2 \cdot 2^n)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

constexpr double eps = 1e-9;
constexpr double PI = acos(-1.0);
int sgn(double x) { return x < -eps ? -1 : x > eps; }

struct Point {
    i64 x, y;
    Point(i64 x = 0, i64 y = 0) : x(x), y(y) {}
};

double dist(Point a, Point b) { 
    return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 
}

vector<Point> p;
vector<Point> q;

int ans = 0;
i64 R;

bool check() {
    if (p.size() <= 1) {
        return true;
    }
    for (int i = 0; i < p.size(); i++) {
        for (int j = 0; j < p.size(); j++) {
            if (dist(p[i], p[j]) > R * R * 4) {
                return false;
            }
        }
    }
    return true;
}

void dfs(int u) {
    if (u && check()) {
        ans = max(ans, int(p.size()));
    }
    if (u == n) {
        return ;
    }
    p.emplace_back(q[u]);
    dfs(u + 1);
    p.pop_back();
    dfs(u + 1);
}

void solve() {
    cin >> n >> R;

    q.resize(n);
    for (int i = 0; i < n; i++) {
        cin >> q[i].x >> q[i].y;
    }

    dfs(0);
    
    assert(ans > 0);

    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   

\(\\\)

L 分衣服
按照编号顺序模拟,考虑用树状数组维护每个点处是否有衣服。当拿走了当前衣服以后,该点置 \(0\) ,那么对于位置为 \(i\) 处的衣服,其贡献为 \(RangeQuery(1, i-1)\),暴力枚举同编号的每件衣服的位置即可。复杂度 \(O(nlogn)\)

点击查看代码
#pragma GCC optimize("unroll-loops, Ofast")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define endl '\n'
#define lowbit(x) x & -x
constexpr i64 Mod = 1000000007;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
i64 n, m, k;

void init() {}

template<typename T>
struct Fenwick {
    using i64 = long long;
    const i64 n;
    std::vector<T> tree;
    Fenwick(i64 n) : n(n), tree(n + 1) {};
    Fenwick(int n) : n(n), tree(n + 1) {};
    Fenwick(double n): n(i64(n)), tree(i64(n) + 1) {};
    T Query(i64 x) {
        T res = 0;
        for (int i = x; i > 0; i -= (i & -i)) {
            res += tree[i];
        }
        return res;
    }
    void upd(i64 l, T z) {
        if (l <= 0) return;
        for (int i = l; i <= n; i += (i & -i)) {
            tree[i] += z;
        }
    }
    T rangeQuery(i64 l, i64 r) {
        if (l > r) {
            return 0;
        }
        return Query(std::min(n, r)) - Query(std::max(0LL, l - 1));
    }
};

constexpr int N = 1e5 + 5;

void solve() {
    cin >> n >> m;

    Fenwick<i64> fen(N);

    vector<vector<int>> pos(n + 1);
    vector<int> p(m + 1);
    for (int i = 1; i <= m; i++) {
        cin >> p[i];
        fen.upd(i, 1);
        pos[p[i]].emplace_back(i);
    }

    i64 ans = 0;

    for (int i = 1; i <= n; i++) {
        for (auto c: pos[i]) {
            ans += fen.rangeQuery(1, c - 1);
            fen.upd(c, -1);
        }
    }

    cout << ans << endl;

}
 
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); 
    init();
    int t = 1;
    // cin >> t;
    while (t--) {
        solve();
    }
 
    return 0; 
}   
posted on 2024-08-08 00:08  _Reborn  阅读(20)  评论(0)    收藏  举报