2019杭电多校第九场

2019杭电多校第九场

熟悉的后半场挂机节奏,又苟进首页了,很快乐

1001. Rikka with Quicksort

upsolved

不是我做的,1e9调和级数分段打表

1002. Rikka with Cake

solved at 01:11

有一个矩形,给你很多射线(射线只有横平竖直的四个方向),问把矩形切成了多少块

队友说答案是交点数加一,作为一个合格的工具人,当然是把队友的想法实现啦

二维坐标离散化枚举纵坐标维护横坐标,常规套路,树状数组也可以做(我是线段树写习惯了根本没想起来还有树状数组)

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

struct P {
    int x, y;
    char op[3];
}a[N];

long long ans;
int b[N], totx, toty;
int T, n, m, K;
vector<int> in[N], out[N], le[N], ri[N];
int sum[N << 2];
void pushup(int rt) {
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

void build(int rt, int l, int r) {
    if(l == r) {
        sum[rt] = 0;
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}

void update(int rt, int l, int r, int pos, int val) {
    if(l == r) {
        sum[rt] += val;
        return;
    }
    int mid = l + r >> 1;
    if(pos <= mid) update(rt << 1, l, mid, pos, val);
    else update(rt << 1 | 1, mid + 1, r, pos, val);
    pushup(rt);
}

int query(int rt, int l, int r, int L, int R) {
    if(L <= l && r <= R)
        return sum[rt];
    int mid = l + r >> 1, ans = 0;
    if(L <= mid) ans += query(rt << 1, l, mid, L, R);
    if(R > mid) ans += query(rt << 1 | 1, mid + 1, r, L, R);
    return ans;
}

int main() {
    scanf("%d", &T);
    while(T--) {
        ans = 0;
        scanf("%d%d%d", &n, &m, &K);
        for(int i = 1; i <= K; ++i) {
            scanf("%d%d%s", &a[i].x, &a[i].y, a[i].op);
            b[i] = a[i].x;
        }
        sort(b + 1, b + K + 1);
        totx = unique(b + 1, b + K + 1) - b - 1;
        for(int i = 1; i <= K; ++i)
            a[i].x = lower_bound(b + 1, b + totx + 1, a[i].x) - b;
        for(int i = 1; i <= K; ++i)
            b[i] = a[i].y;
        sort(b + 1, b + K + 1);
        toty = unique(b + 1, b + K + 1) - b - 1;
        for(int i = 1; i <= K; ++i)
            a[i].y = lower_bound(b + 1, b + toty + 1, a[i].y) - b;
        build(1, 1, totx);
        for(int i = 1; i <= K; ++i)
            in[i].clear(), out[i].clear(), le[i].clear(), ri[i].clear();
        for(int i = 1; i <= K; ++i) {
            if(a[i].op[0] == 'U')
                in[a[i].y].push_back(a[i].x);
            else if(a[i].op[0] == 'D') {
                out[a[i].y].push_back(a[i].x);
                update(1, 1, totx, a[i].x, 1);
            }
            else if(a[i].op[0] == 'L')
                le[a[i].y].push_back(a[i].x);
            else
                ri[a[i].y].push_back(a[i].x);
        }
        for(int i = 1; i <= toty; ++i) {
            for(auto f: in[i])
                update(1, 1, totx, f, 1);
            int l = 0, r = 1e9;
            for(auto f: le[i])
                l = max(l, f);
            for(auto f: ri[i])
                r = min(r, f);
            if(l >= r)
                ans += sum[1];
            else {
                if(l != 0)
                    ans += query(1, 1, totx, 1, l);
                if(r != 1e9)
                    ans += query(1, 1, totx, r, totx);
            }
            //cout << "ans = " << ans << endl;
            for(auto f: out[i])
                update(1, 1, totx, f, -1);
        }
        printf("%lld\n", ans + 1);
    }
    return 0;
}

1003. Rikka with Mista

upsolved

至多40个数,对每一个子集求其所有数的和的十进制表示里\(4\)的个数,对所有子集求和

先折半,然后按十进制位考虑,双指针查询(不用多次排序,只要在一次完整的基数排序的过程中计算就好了)

#include <bits/stdc++.h>
using namespace std;
using LL = long long;

struct num {
    LL l, r;
};

LL ans, base;
vector<num> x, y, A[10], B[10];
int T, n, p, q, w[50];

void dfs(int now, int step, LL tmp, vector<num> &x) {
    if(now == step) {
        x.push_back({tmp, 0});
        return;
    }
    dfs(now + 1, step, tmp, x);
    dfs(now + 1, step, tmp + w[now], x);
}

LL get0(vector<num> &A, vector<num> &B, LL limit) {
    LL res = 0;
    int j = B.size() - 1;
    for(int i = 0; i < A.size(); ++i) {
        while(j >= 0 && A[i].r + B[j].r >= limit) j--;
        res += j + 1;
    }
    return res;
}

LL get1(vector<num> &A, vector<num> &B, LL limit) {
    LL res = 0;
    int j = 0;
    for(int i = (int)A.size() - 1; ~i; --i) {
        while(j < B.size() && A[i].r + B[j].r < limit) j++;
        res += (int)B.size() - j;
    }
    return res;
}

int main() {
    scanf("%d", &T);
    while(T--) {
        ans = 0; base = 1;
        x.clear(); y.clear();
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
            scanf("%d", &w[i]);
        p = n / 2;
        dfs(0, p, 0, x);
        dfs(p, n, 0, y);
        for(int bit = 1; bit <= 9; ++bit) {
            for(int i = 0; i <= 9; ++i)
                A[i].clear(), B[i].clear();
            for(auto f: x)
                A[f.l % 10].push_back({f.l / 10, f.r});
            for(auto f: y)
                B[f.l % 10].push_back({f.l / 10, f.r});
            for(int i = 0; i <= 9; ++i) {
                int j1 = (14 - i) % 10, j2 = (13 - i) % 10;
                ans += get0(A[i], B[j1], base) + get1(A[i], B[j2], base);
            }
            int nowx = 0, nowy = 0;
            for(int i = 0; i <= 9; ++i) {
                for(auto f: A[i])
                    x[nowx++] = (num){f.l, f.r + i * base};
                for(auto f: B[i])
                    y[nowy++] = (num){f.l, f.r + i * base};
            }
            base *= 10;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

1005. Rikka with Game

solved at 00:16

一个字符串,两个人轮流操作,每个人有两种操作,一是立即终止游戏,二是将一个位置的字符变成下一个字符\((a->b, b->c, ..., z->a)\)

第一个人想最小化字典序,第二个人想最大化字典序,求最后的字符串

想一想,发现是不考虑前缀\(y\), 如果首个字母是\(z\)则变成\(b\),否则不变

1006. Rikka with Coin

solved at 00:51(+7)

有10,20,50,100四种面额的硬币,有\(n\)种商品,每种价格已知,求最少的硬币数使得硬币面额能恰好组成任意一种商品

设最贵的为\(w\),面额100的要么是\(w/100\)个要么少一个,前三种暴力枚举

一开始max写成min了一直TLE...

#include <bits/stdc++.h>
using namespace std;

const int N = 110;

int T, n, w[N];
int ans, tmp;

int vis[22];

bool judge(int x, int y, int z, int d) {
    memset(vis, 0, sizeof(vis));
    vis[0] = 1;
    for(int i = 1; i <= x; ++i) {
        for(int j = 20; j >= 1; --j)
            vis[j] |= vis[j - 1];
    }
    for(int i = 1; i <= y; ++i) {
        for(int j = 20; j >= 2; --j)
            vis[j] |= vis[j - 2];
    }
    for(int i = 1; i <= z; ++i) {
        for(int j = 20; j >= 5; --j)
            vis[j] |= vis[j - 5];
    }
    for(int i = 1; i <= n; ++i) {
        bool flag = 0;
        int t = w[i] % 10;
        while(t <= 20) {
            if(t + d * 10 >= w[i] && vis[t]) {flag = true; break;}
            t += 10;
        }
        if(!flag) return false;
    }
    return true;
}

int main() {
    scanf("%d", &T);
    while(T--) {
        bool flag = true;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &w[i]);
            if(w[i] % 10)
                flag = false;
            w[i] /= 10;
        }
        if(!flag) {
            puts("-1");
            continue;
        }
        sort(w + 1, w + n + 1);
        tmp = w[n] / 10;
        ans = 1e9;
        for(int a = 0; a <= 10; ++a) {
            for(int b = 0; b <= 5; ++b) {
                for(int c = 0; c <= 2; ++c) {
                    for(int d = max(0, tmp - 1); d <= tmp; ++d) {
                        if(judge(a, b, c, d)) {
                            ans = min(ans, a + b + c + d);
                        }
                    }
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

1007. Rikka with Travel

solved at 02:13

给定一颗树,求满足存在一条点数为\(i\)的路径和一条点数为\(j\)的路径且两条路径不相交的点对\((i, j)\)的数量\((1<=n<=1e5)\)

我又是个工具人

树形dp

枚举一条边把树切成两半,然后两边分别求直径,假设为a, b, 那么\((1<=i<=a\&\&1<=j<=b)\)的点对都满足条件(\(i, j\)可以互换)

考虑两遍dfs, 第一遍处理出这个点的子树的直径,这个点往下延伸的最远的三个儿子以及长度,这个点的最大以及次大儿子直径

第二遍dfs处理出挖掉这个点的子树之后树的直径,可以用之前处理出的信息维护出来

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

long long answer;
int v[N];
int T, n, x, y;
vector<int> G[N];
int mx[N][3], p[N][3], ans[N][2];
int mxson[N][2], ps[N][2];

void dfs(int rt, int fa) {
    mx[rt][0] = 1; mx[rt][1] = -1e9; mx[rt][2] = -1e9;
    p[rt][0] = rt; p[rt][1] = -1; mx[rt][2] = -1;
    ans[rt][0] = 1;
    mxson[rt][0] = mxson[rt][1] = -1e9;
    ps[rt][0] = ps[rt][1] = -1;
    for(int v: G[rt]) {
        if(v == fa) continue;
        dfs(v, rt);
        if(mx[rt][2] < mx[v][0] + 1) {
            mx[rt][2] = mx[v][0] + 1;
            p[rt][2] = v;
        }
        if(mx[rt][2] > mx[rt][1]) {
            swap(mx[rt][2], mx[rt][1]);
            swap(p[rt][2], p[rt][1]);
        }
        if(mx[rt][1] > mx[rt][0]) {
            swap(mx[rt][1], mx[rt][0]);
            swap(p[rt][1], p[rt][0]);
        }
        if(ans[v][0] > mxson[rt][1]) {
            mxson[rt][1] = ans[v][0];
            ps[rt][1] = v;
        }
        if(mxson[rt][1] > mxson[rt][0]) {
            swap(mxson[rt][1], mxson[rt][0]);
            swap(ps[rt][1], ps[rt][0]);
        }
        ans[rt][0] = max(ans[rt][0], ans[v][0]);
    }
    ans[rt][0] = max(mx[rt][0] + mx[rt][1] - 1, ans[rt][0]);
}

void dfs2(int rt, int fa, int tmp, int len) {
    ans[rt][1] = tmp;
    for(int v: G[rt]) {
        if(v == fa) continue;
        int new_tmp = tmp;
        int new_len = len + 1;
        if(p[rt][0] != v) {
            new_len = max(new_len, mx[rt][0]);
        }
        if(p[rt][1] != v) {
            new_len = max(new_len, mx[rt][1]);
        }
        vector<int> vv;
        vv.push_back(len + 1);
        if(p[rt][0] != v)
            vv.push_back(mx[rt][0]);
        if(p[rt][1] != v)
            vv.push_back(mx[rt][1]);
        if(p[rt][2] != v)
            vv.push_back(mx[rt][2]);
        sort(vv.begin(), vv.end(), greater<int>());
        new_tmp = max(new_tmp, vv[0] + vv[1] - 1);
        if(ps[rt][0] != v)
            new_tmp = max(new_tmp, mxson[rt][0]);
        if(ps[rt][1] != v)
            new_tmp = max(new_tmp, mxson[rt][1]);
        dfs2(v, rt, new_tmp, new_len);
    }
}

int main() {
    scanf("%d", &T);
    while(T--) {
        answer = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) G[i].clear();
        for(int i = 1; i < n; ++i) {
            scanf("%d%d", &x, &y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        dfs(1, 0);
        dfs2(1, 0, 0, 0);
        memset(v, 0, sizeof(int) * (n + 3));
        for(int i = 1; i <= n; ++i) {
            int a = ans[i][0], b = ans[i][1];
            v[a] = max(v[a], b);
            v[b] = max(v[b], a);
        }
        for(int i = n; i; --i)
            v[i] = max(v[i], v[i + 1]);
        for(int i = 1; i <= n; ++i) {
            answer += v[i];
        }
        printf("%lld\n", answer);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/tusikalanse/p/11385167.html

时间: 2024-10-08 03:26:05

2019杭电多校第九场的相关文章

2019 杭电多校 第九场

2019 Multi-University Training Contest 9 补题链接:2019 Multi-University Training Contest 9 1005 Rikka with Game (HDU 6684) 题意 Rikka 和 Yuta 玩游戏.给定一个字符串.两人轮流对字符串操作.可以选择结束游戏,也可以改变其中一个字符,改变规则是:\(a\rightarrow b,b\rightarrow c,-,y\rightarrow z,z\rightarrow a.\

Rikka with Game[技巧]----2019 杭电多校第九场:1005

Rikka with Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Though both Rikka and Yuta are busy with study, on their common leisure, they

2019年杭电多校第九场07题(HDU6686+树形dp)

目录 题目链接 题意 思路 代码 题目链接 传送门 题意 定义\(L(a,b)\)为结点\(a\)到结点\(b\)的路径上的结点数,问有种\(pair(L(a,b),L(c,d))\)取值,其中结点\(a\)到结点\(b\)的路径与结点\(c\)到结点\(d\)的路径没有交叉. 思路 我们很容易想到要想两条路径不交叉,那么\(a,b\)与\(c,d\)必定在两棵不同的子树中,假设第一棵子树的直径位\(L1\),第二棵子树的直径为\(L2\),那么我们可以得知\([1,L1]\)必定可以与\([1

【2019.07.22】2019杭电多校第一场

补题地址:http://acm.hdu.edu.cn/listproblem.php?vol=56 题号:6578-6590 1001: 1002:线性基 https://blog.csdn.net/Cassie_zkq/article/details/96979461 1003: 1004: 1005:? 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 自闭场,但补题能学到好多算法和思维,继续加油鸭- 原文地址:https://www.cnblo

2019 杭电多校 第一场

2019 Multi-University Training Contest 1 补题链接:2019 Multi-University Training Contest 1 1002 Operation (HDU-6579) 题意 给定包含 \(n\) 个数的序列,\(m\) 个询问.询问有两种操作,操作 \(0\) 表示在数组最后添加一个新元素,操作 \(1\) 表示查询区间 [l,r] 的子集的异或最大值. 询问强制在线. 题解 线性基 贪心 1004 Vacation (HDU-6581)

2019 杭电多校 第二场

2019 Multi-University Training Contest 2 补题链接:2019 Multi-University Training Contest 2 1005 Everything Is Generated In Equal Probability (HDU-6595) 题意 给出一个整数 \(N\),在 \([1,N]\) 中随机生成一个 \(n\).然后生成长度为 \(n\) 的全排列 \([1, n]\). 对该排列运行一个程序,程序先求当前排列的逆序对对数,然后随

杭电多校第九场 HDU6415 Rikka with Nash Equilibrium dp

Rikka with Nash Equilibrium Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1251    Accepted Submission(s): 506 Problem Description Nash Equilibrium is an important concept in game theory. Ri

2019 杭电多校第一场

D Vacation 题解:题目给出两个人要去旅行,在他们前面有n辆车,每辆车有长度以及车首部到stopline 的距离以及每辆车的最大速度,后面的车不能超过前面的车.问你他们两个的车首部到达stopline的最短时间. 思路:二分答案,求出最后一辆车停在的位置. 参考代码: #include<bits/stdc++.h> using namespace std; #define mkp make_pair<int,int> typedef long long ll; const

2019杭电多校第一场hdu6581 Vacation

Vacation 题目传送门 解题思路 一开始的时候所有车都是是按照自己原来的速度行驶,直到有一辆车x追上前面的那辆车y,此时的变化只有,1.x的速度变为y的速度2.x后面的车追上x的时间变短.所以我们只要利用优先队列,每一次都找到会在最短的时间内追上前面那辆车的x,不断更新这个过程就好了. 以及实现中的一些细节,1.对于已经追上和被追上的两辆车,我们可以看成一辆火车,每辆车就是一节车厢,其速度就是最前面那节车厢的速度,当一辆火车追上另一辆的时候,新的火车头就是前面被追上车厢的火车头,新的火车尾