zoukankan      html  css  js  c++  java
  • 2019HDU多校 Round10

    Solved:3

    Rank:214

    08 Coin

    题意:n组硬币 每组有两个 分别有自己的价值 每组的第一个被拿了之后才能拿第二个

       问拿1,2....2n个硬币的最大价值

    题解:之前贪心带反悔的做法写不出来... 然后学习下别人的贪心策略 考虑从0或1开始 每次拿两个

       那么要么是拿一组 要么是拿两个散装最大的 然后模拟一下

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 1e5 + 5;
    
    int a[MAXN], b[MAXN], vis[MAXN], vvis[MAXN], now;
    int ans[MAXN << 1];
    struct node {
        int a, b, id;
    
        friend bool operator < (node A, node B) {
            if(A.a + A.b == B.a + B.b) return A.id < B.id;
            else return A.a + A.b < B.a + B.b;
        }
    };
    node sum[MAXN];
    priority_queue<node> que;
    
    void solve(int i) {
        node tmp1 = {0, 0, 0}, tmp2 = {0, 0, 0}, tmp3 = {0, 0, 0};
        while(now >= 1 && vis[now]) now--;
        if(now >= 1) tmp1 = sum[now];
    
        while(!que.empty() && vvis[que.top().id]) que.pop();
        if(!que.empty()) tmp2 = que.top(), que.pop();
        while(!que.empty() && vvis[que.top().id]) que.pop();
        if(!que.empty()) tmp3 = que.top(), que.pop();
    
        if(tmp1.a + tmp1.b > tmp2.a + tmp2.b + tmp3.a + tmp3.b) {
            ans[i] = ans[i - 2] + tmp1.a + tmp1.b;
            vis[now] = 1; vvis[now] = 1;
            que.push(tmp2); que.push(tmp3);
        } else {
            ans[i] = ans[i - 2] + tmp2.a + tmp2.b + tmp3.a + tmp3.b;
            if(tmp2.a) {
                vis[tmp2.id] = 1;
                que.push((node){0, sum[tmp2.id].b, tmp2.id});
            } else vvis[tmp2.id] = 1;
            if(tmp3.a) {
                vis[tmp3.id] = 1;
                que.push((node){0, sum[tmp3.id].b, tmp3.id});
            } else vvis[tmp3.id] = 1;
        }
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while(T--) {
            int n;
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) scanf("%d%d", &a[i], &b[i]), sum[i].a = a[i], sum[i].b = b[i], sum[i].id = i, vis[i] = vvis[i] = 0;
            sort(sum + 1, sum + 1 + n);
    
            now = n;
            while(!que.empty()) que.pop();
            ans[0] = 0;
            for(int i = 1; i <= n; i++) que.push((node){sum[i].a, 0, i});
            for(int i = 2; i <= n * 2; i += 2) solve(i);
    
    
            while(!que.empty()) que.pop();
            now = n;
            for(int i = 1; i <= n; i++) que.push((node){sum[i].a, 0, i}), vis[i] = vvis[i] = 0;
            node t1 = que.top(); que.pop();
            ans[1] = t1.a; que.push((node){0, sum[t1.id].b, t1.id}); vis[t1.id] = 1;
            for(int i = 3; i <= n * 2; i += 2) solve(i);
    
            for(int i = 1; i <= n * 2; i++) {
                if(i != n * 2) printf("%d ", ans[i]);
                else printf("%d
    ", ans[i]);
            }
        }
        return 0;
    }
    Coin

    11 Make Rounddog Happy (启发式分治)

    题意:1e5个数 统计多少个区间满足 区间最大 - 区间长度 <= k 且区间内没有相同的数

    题解:都说这个题是这种套路.... 用st表预处理区间最大值 然后再预处理每个数往左往右没有相同数的最远距离

       然后每次找到区间最大值 暴力从区间小的一边枚举答案 然后分治

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 1e6 + 5;
    ll ans;
    int n, K;
    int a[MAXN];
    int st[MAXN][21], lg[MAXN];
    int L[MAXN], R[MAXN];
    int vis[MAXN];
    
    void solve(int l, int r) {
        if(l > r) return;
    
        int k = lg[r - l + 1];
        int pos;
        if(a[st[l][k]] >= a[st[r - (1 << k) + 1][k]]) pos = st[l][k];
        else pos = st[r - (1 << k) + 1][k];
    
        if(pos - l <= r - pos) {
            for(int i = l; i <= pos; i++) {   //枚举左端点
                int rr = a[pos] - K + i - 1;  //移项之后 满足rr <= 区间右端点就是满足题意的
                rr = max(rr, pos);            //大于pos 最大值才成立
    
                int tr = min(R[i], r);
                if(tr >= rr) ans += 1LL * (tr - rr + 1);
            }
        } else {
            for(int i = r; i >= pos; i--) {
                int ll = K - a[pos] + i + 1;
                ll = min(ll, pos);
    
                int tl = max(L[i], l);
                if(tl <= ll) ans += 1LL * (ll - tl + 1);
            }
        }
        solve(l, pos - 1); solve(pos + 1, r);
    }
    
    int main() {
        lg[0] = -1;
        for(int i = 1; i <= MAXN - 2; i++) lg[i] = lg[i >> 1] + 1;
    
        int T;
        scanf("%d", &T);
        while(T--) {
            ans = 0;
            scanf("%d%d", &n, &K);
            for(int i = 1; i <= n; i++) scanf("%d", &a[i]), st[i][0] = i;
    
            for(int i = 1; i <= 20; i++)
                for(int j = 1; j <= n + 1 - (1 << i); j++) {
                    if(a[st[j + (1 << (i - 1))][i - 1]] >= a[st[j][i - 1]]) st[j][i] = st[j + (1 << (i - 1))][i - 1];
                    else st[j][i] = st[j][i - 1];
                }
    
            memset(vis, 0, sizeof(vis)); L[1] = 1; vis[a[1]] = 1;
            for(int i = 2; i <= n; i++) {
                if(vis[a[i]]) L[i] = max(L[i - 1], vis[a[i]] + 1);
                else L[i] = L[i - 1];
                vis[a[i]] = i;
            }
    
            memset(vis, 0, sizeof(vis)); R[n] = n; vis[a[n]] = n;
            for(int i = n - 1; i >= 1; i--) {
                if(vis[a[i]]) R[i] = min(R[i + 1], vis[a[i]] - 1);
                else R[i] = R[i + 1];
                vis[a[i]] = i;
            }
            solve(1, n);
            printf("%lld
    ", ans);
        }
        return 0;
    }
    Make Rounddog Happy
  • 相关阅读:
    面试题23:从上往下打印二叉树
    面试题22:栈的压入、弹出序列
    【opencv基础】imwrite函数与图像存储质量
    【c++基础】从json文件提取数据
    【图像处理基础】LBP特征
    【机器学习基础】SVM实现分类识别及参数调优(二)
    【leetcode】14-LongestCommonPrefix
    【leetcode】13-Roman2Integer
    【leetcode】9-PalindromeNumber
    【leetcode】7-ReverseInteger
  • 原文地址:https://www.cnblogs.com/lwqq3/p/11449279.html
Copyright © 2011-2022 走看看