2022“杭电杯”中国大学生算法设计超级联赛(3)题解

这篇博客涵盖了四道编程竞赛题目,包括CyberLanguage的签到题,BossRush的状压DP问题,TwoPermutations的计数DP解法,以及Taxi的KD树应用。博主详细解析了每道题目的思路和解决方案,涉及排序、二分查找、动态规划和空间数据结构等算法知识。

1003 Cyber Language

QAQ 签到题~

1009 Package

wa了十发 ,栓Q

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

struct qwq {
    int l, r;
    int id;
    bool operator<(const qwq& b) const {
        return r == b.r ? l < b.l : r < b.r;
    }
};

void solve() {
    int k, n;
    //cin >> n >> k;
    n = read(); k = read();
    set<qwq> pq;
    vector<qwq> vq(n + 1);
    vector<pii> st;
    for (int i = 1; i <= n; i++) {
        //cin >> vq[i].l >> vq[i].r;
        vq[i].l = read(); vq[i].r = read();
        st.push_back({ vq[i].l, -i });
        st.push_back({ vq[i].r, i });
        vq[i].id = i;
    }
    sort(st.begin(), st.end());
    int ans = 0;
    for (auto it : st) {
        if (it.second < 0) pq.insert(vq[-it.second]);
        else if (vq[it.second].l != -1) {
            ans++;
            pq.erase(vq[it.second]);
            vq[it.second].l = -1;
            for (int i = 1; i < k && !pq.empty(); i++) {
                auto id = pq.begin()->id;
                vq[id].l = -1;
                pq.erase(pq.begin());
            }
        }
    }
    printf("%d\n", ans);
}

int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(0); cout.tie(0);
    int T = 1;
    //cin >> T;
    T = read();
    while (T--) solve();
    return 0;
}

1002 Boss Rush

状压dp

dp[i].firstdp[i].firstdp[i].first 来记录攻击力
dp[i].seconddp[i].seconddp[i].second 来记录时间

二分时间 判断dp过程中的取到的最大值是否能够到达 h

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

ll read() {
    ll x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

struct SK {
    int t, len;
    vector<ll> atk;
};
typedef pair<ll, int> pll;

bool check(vector<SK>& v, int mxt, ll h) {
    vector<pll> dp(1 << v.size());
    ll r = 0;
    for (int i = 1; i < (1 << v.size()); i++) {
        for (int j = 0; j < v.size(); j++) {
            if (i & (1 << j)) {
                pll x = dp[i ^ (1 << j)];
                int p = min(v[j].len,( mxt - x.second + 1));
                if (p < 0) continue;
                x.first += v[j].atk[p];
                x.second += v[j].t;
                if (x.first > dp[i].first) dp[i] = x;
                r = max(r, x.first);
                if (p == v[j].len) break;
            }
        }
    }
    return r >= h;
}

void solve() {
    int n; ll h;
    n = read();
    h = read();

   // cout << h << endl;
    vector<SK> v(n);
    for (int i = 0; i < n; i++) {
        v[i].t = read();
        v[i].len = read();
        v[i].atk.resize(v[i].len + 1);
        ll x;
        for (int j = 1; j <= v[i].len; j++) {
            x = read();
            v[i].atk[j] = v[i].atk[j - 1] + x;
        }
    }
    int l = 0, r = 2e6;
    int ans = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (check(v, mid, h)) {
            r = mid - 1;
            ans = mid;
        }
        else {
            l = mid + 1;
        }
    }
    printf("%d\n", ans);
}

int main() {
  //  ios::sync_with_stdio(false);
  //  cin.tie(0); cout.tie(0);
    int T = 1;
    T = read();
    while (T--) solve();
    return 0;
}

1012 Two Permutations

计数dp

dp[i][j].adp[i][j].adp[i][j].a 来表示前面用了多少个a序列 用 dp[i][j].bdp[i][j].bdp[i][j].b 来表示前面用了多少个b数组,用 dp[i][j].valdp[i][j].valdp[i][j].val 来表示构成这种方法会有几种方式
开一个动态 mapmapmap 来存储答案
再把 mapmapmap 的值赋值到 dpdpdp 上面去

#include<bits/stdc++.h>

using namespace std;

#define int long long
typedef long long ll;
typedef pair<int, int> pii;
int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

const int mod = 998244353;
const int N = 3e5 + 10;

int a[N], b[N];
int c[N * 2];

struct node {
    int a, b;
    int val;
};

vector<node> dp[N * 2];

void solve() {
   
    int n = read();
    //cin >> n;
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i <= n; i++) b[i] = read();
    for (int i = 1; i <= 2*n; i++) {
        c[i] = read();
    }
    for (int i = 0; i <= 2 * n; i++) dp[i].clear();
    dp[0].push_back({ 0,0,1 });
    for (int i = 1; i <= 2 * n; i++) {
        map<pair<int, int>, int> mp;
        for (int j = 0; j < dp[i - 1].size(); j++) {
            if (a[dp[i - 1][j].a + 1] == c[i]) {
                mp[{dp[i - 1][j].a+1, dp[i - 1][j].b}] += dp[i - 1][j].val;
                mp[{dp[i - 1][j].a+1, dp[i - 1][j].b }] %= mod;
            }
            if (b[dp[i - 1][j].b + 1] == c[i]) {
                mp[{dp[i - 1][j].a, dp[i - 1][j].b+1}] += dp[i - 1][j].val;
                mp[{dp[i - 1][j].a, dp[i - 1][j].b + 1}] %= mod;
            }
        }
        for (auto it : mp) dp[i].push_back({ it.first.first, it.first.second, it.second });
    }
    ll ans = 0;
    for (auto it : dp[2 * n]) ans = (ans + it.val) % mod;
    printf("%lld\n", ans);
}

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

1011 Taxi

kd树

(队友写的 bushi很懂

#include<bits/stdc++.h>

using namespace std;

#define int long long

const int INF = 1e9+7;
const int N = 5e5+7;


namespace KD_Tree {
    struct Dot {
        int d[2], mn[2], mx[2], l, r, sz, sum, val;
        Dot() { l = r = 0; }
        Dot(int x, int y, int c) {
            d[0] = x;
            d[1] = y;
            val = c;
            l = r = sz = sum = 0;
        }
        int& operator[](int x) { return d[x]; }
    };
    int D, dcnt = 0, pt[N];
    Dot T[N];
    Dot p[N];
    bool operator<(Dot a, Dot b) { return a[D] < b[D]; }
    inline void umax(int& a, int b) {
        if (a < b) a = b;
    }
    inline void umin(int& a, int b) {
        if (a > b) a = b;
    }
    inline bool cmp(int x, int y) { return T[x][D] < T[y][D]; }
    inline void up(int x) {
        T[x].sz = T[T[x].l].sz + T[T[x].r].sz + 1;
        T[x].sum = max(T[T[x].l].sum, max(T[T[x].r].sum, T[x].val));
        T[x].mn[0] = T[x].mx[0] = T[x][0];
        T[x].mn[1] = T[x].mx[1] = T[x][1];
        if (T[x].l) {
            umax(T[x].mx[0], T[T[x].l].mx[0]);
            umin(T[x].mn[0], T[T[x].l].mn[0]);
            umax(T[x].mx[1], T[T[x].l].mx[1]);
            umin(T[x].mn[1], T[T[x].l].mn[1]);
        }
        if (T[x].r) {
            umax(T[x].mx[0], T[T[x].r].mx[0]);
            umin(T[x].mn[0], T[T[x].r].mn[0]);
            umax(T[x].mx[1], T[T[x].r].mx[1]);
            umin(T[x].mn[1], T[T[x].r].mn[1]);
        } 
    }
    // 离线建树时,只加点,不构树,最后build
    inline void AddDot(int x, int y, int c) {
        ++dcnt;
        pt[dcnt] = dcnt;
        p[dcnt][0] = x;
        p[dcnt][1] = y;
        p[dcnt].val = c;
    }
    // 曼哈顿距离估价函数
    inline int dist(int p1, int px, int py) {
        int dis = 0;
        if (px > T[p1].mn[0]) dis += abs(T[p1].mn[0] - px);
        if (px < T[p1].mx[0]) dis += abs(px - T[p1].mx[0]);
        if (py > T[p1].mn[1]) dis += abs(T[p1].mn[1] - py);
        if (py < T[p1].mx[1]) dis += abs(py - T[p1].mx[1]);
        return min(dis, T[p1].sum);
    }

    int ans = 0;
    inline void ask(int x, int px, int py) {
        int dl, dr, d0 = min(T[x].val, abs(T[x][0] - px) + abs(T[x][1] - py));
        if (d0 > ans) ans = d0;
        dl = T[x].l ? dist(T[x].l, px, py) : 0;
        dr = T[x].r ? dist(T[x].r, px, py) : 0;
        if (dl > dr) {
            if (dl > ans) ask(T[x].l, px, py);
            if (dr > ans) ask(T[x].r, px, py);
        } else {
            if (dr > ans) ask(T[x].r, px, py);
            if (dl > ans) ask(T[x].l, px, py);
        } 
    }

    int QueryMax(int x, int px, int py) {
        ans = 0;
        ask(x, px, py);
        return ans;
    }

    // 建树
    int build(int l, int r, int now) {
        int mid = (l + r) >> 1;
        D = now;
        nth_element(p + l, p + mid, p + r + 1);
        T[mid] = p[mid];
        for (int i = 0; i < 2; i++) T[mid].mn[i] = T[mid].mx[i] = T[mid][i];
        if (l < mid) T[mid].l = build(l, mid - 1, now ^ 1);
        if (r > mid) T[mid].r = build(mid + 1, r, now ^ 1);
        up(mid);
        return  mid;
    }
}


void solve() {
    KD_Tree::dcnt = 0;
    int n, q;
    cin >> n >> q;
    for (int i = 1; i <= n; i++) {
        int x, y, w;
        cin >> x >> y >> w;
        KD_Tree::AddDot(x, y, w);
    }
    int root = KD_Tree::build(1, n, 0);
    while (q--) {
        int x, y;
        cin >> x >> y;
        cout << KD_Tree::QueryMax(root, x, y) << '\n';
    }
}
#undef int
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
   
    //freopen("1011.out", "w", stdout);
    //freopen("1011.in", "r", stdin);
    int T = 1;
    cin >> T;
    while (T--) solve();
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值