CF-595

题目传送门

A .Yet Another Dividing into Teams

sol:原先是用比较复杂的方法来解的,后来学弟看了一眼,发现不是1就是2,当出现两个人水平相差为1就分成两组,1组全是奇数,1组全是偶数,必然符合题意。

  • 思维
    #include "bits/stdc++.h"
    using namespace std;
    #define debug puts("what the fuck");
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 110;
    bool vis[MAXN];
    int main() {
        int t, n, m;
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            bool ok = true;
            memset(vis, false, sizeof(vis));
            for (int i = 1; i <= n; i++) {
                scanf("%d", &m);
                vis[m] = true;
                if (vis[m - 1] || vis[m + 1]) ok = false;
            }
            if (ok) puts("1");
            else puts("2");
        }
        return 0;
    }
    View Code

     

B. Books Exchange

sol:很裸的并查集,i和p[i]属于同一个集合,求每个点所在集合的大小

  • 并查集
    #include "bits/stdc++.h"
    using namespace std;
    #define debug puts("what the fuck");
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 2e5 + 10;
    int pre[MAXN], cnt[MAXN];
    int find(int i) {
        if (pre[i] == i) return i;
        return pre[i] = find(pre[i]);
    }
    int main() {
        int t, n, m;
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                cnt[i] = 1;
                pre[i] = i;
            }
            for (int i = 1; i <= n; i++) {
                scanf("%d", &m);
                int u = find(i);
                int v = find(m);
                if (u != v) {
                    pre[u] = v;
                    cnt[v] += cnt[u];
                }
            }
            for (int i = 1; i <= n; i++)
                printf("%d ", cnt[find(i)]);
            puts("");
        }
        return 0;
    }
    View Code

     

C1. Good Numbers (easy version)

sol:由于n比较小,所以我们可以暴力罗列good number,pow(3, 10)已经大于n的最大范围10000,所以罗列到3的10次方够了,再组合一下,排序后用二分去搜就好了。

  • 暴力组合
    #include "bits/stdc++.h"
    using namespace std;
    #define debug puts("what the fuck");
    typedef long long LL;
    typedef pair<int, int> PII;
    int p[20] = {1};
    vector<int> v;
    void init() {
        for (int i = 1; i <= 10; i++)
            p[i] = 3 * p[i - 1];
        for (int i = 1; i <= (1 << 10); i++) {
            int sum = 0;
            for (int j = 0; j <= 10; j++)
                if (i & (1 << j)) sum += p[j];
            v.push_back(sum);
        }
    }
    int main() {
        int t, n;
        scanf("%d", &t);
        init();
        sort(v.begin(), v.end());
        while (t--) {
            scanf("%d", &n);
            printf("%d\n", *lower_bound(v.begin(), v.end(), n));
        }
        return 0;
    }
    View Code

     

C2. Good Numbers (hard version)

sol:细看这题感觉和进制有关,把n转成3进制后找到第一个大于等于n并且所以三进制位不为2的数;

  • 进制
    #include "bits/stdc++.h"
    using namespace std;
    #define debug puts("what the fuck");
    typedef long long LL;
    typedef pair<int, int> PII;
    int p[60];
    int main() {
        int t;
        LL n, pos;
        scanf("%d", &t);
        while (t--) {
            scanf("%lld", &n);
            memset(p, 0, sizeof(p));
            pos = 0;
            while (n) {
                p[pos++] = n % 3;
                n /= 3;
            }
            int k = pos - 1;
            while (k > 0 && p[k] != 2) k--; // 从高位往低位搜找到第一个2
            for (int i = k - 1; i >= 0; i--) p[i] = 0; // 第k位加1,那么k之前的位可以全部为0了,一定不会小于n
            while (p[k] == 2) { //进位
                p[k] = 0;
                p[++k] ++;
            }
            pos = max(pos, k + 1LL);
            LL sum = 0, pp = 1;
            for (int i = 0; i < pos; i++) {
                if (p[i] == 1) sum += pp;
                pp *= 3;
            }
            printf("%lld\n", sum);
        }
        return 0;
    }
    View Code

     

D. Too Many Segments 

sol:用差分确定覆盖每个点的线段有多少条,对于点i,如果覆盖的线段数量大于k,删掉覆盖该点的右端点最远的线段,可以用优先队列找这样的线段。就是需要两个排序方式。

  • 贪心,差分
    #include "bits/stdc++.h"
    using namespace std;
    #define debug puts("what the fuck");
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 2e5 + 10;
    struct Seg {
        int l, r;
        int index;
        friend bool operator < (Seg a, Seg b) {return a.r < b.r;}
    } a[MAXN];
    priority_queue<Seg> que;
    bool cmp(Seg a, Seg b) {return a.l < b.l;}
    vector<int> ans;
    int cnt[MAXN], pos, sum;
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%d%d", &a[i].l, &a[i].r);
            a[i].index = i;
        }
        sort(a + 1, a + 1 + n, cmp);
        for (int i = 1; i <= n; i++) {
            while (pos < a[i].l) sum += cnt[++pos];
            que.push(a[i]);
            sum ++, cnt[a[i].r + 1] --;
            if (sum > m) {
                sum --;
                Seg s = que.top();
                que.pop();
                cnt[s.r + 1] ++;
                ans.push_back(s.index);
            }
        }
        printf("%d\n", ans.size());
        for (auto index : ans) printf("%d ", index);
        return 0;
    }
    View Code

     

E. By Elevator or Stairs?

sol:dp,dp[0][i]表示从a[i]到1的最少时间,dp[1][i]表示从b[i]到1的最少时间。代码中直接把a、b数组当dp[0]和dp[1]来用了;

  • 动态规划
    #include "bits/stdc++.h"
    using namespace std;
    #define debug puts("what the fuck");
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 2e5 + 10;
    int a[MAXN], b[MAXN];
    int main() {
        int n, c;
        scanf("%d%d", &n, &c);
        a[1] = 0, b[1] = c;
        for (int i = 2; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 2; i <= n; i++) scanf("%d", &b[i]);
        for (int i = 1; i <= n; i++) {
            a[i] += min(a[i - 1], b[i - 1]);
            b[i] += min(a[i - 1] + c, b[i - 1]);
            printf("%d ", min(a[i], b[i]));
        }
        return 0;
    }
    View Code

     

F. Maximum Weight Subset

sol:树形dp,dp[u][dep]表示u子树中距离u最近的选取点离u的距离不小于dep的最大权重。要注意的是合并的时候两颗子树间的选取点距离也不能小于等于k;

  • 树形dp
    #include "bits/stdc++.h"
    using namespace std;
    #define debug puts("what the fuck");
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 210;
    int w[MAXN];
    int dp[MAXN][MAXN];
    vector<int> edge[MAXN];
    int n, k;
    void dfs(int u, int fa) {
        for (auto v : edge[u]) {
            if (v == fa) continue;
            dfs(v, u);
        }
        dp[u][0] = w[u];
        for (auto v : edge[u]) {
            if (v == fa) continue;
            dp[u][0] += dp[v][k];
        }
        for (int dep = 1; dep <= k; dep++) {
            for (auto v : edge[u]) {
                if (v == fa) continue;
                int sum = dp[v][dep - 1];
                for (auto other : edge[u]) {
                    if (other == fa || other == v) continue;
                    sum += dp[other][max(dep - 1, k - dep)];
                }
                dp[u][dep] = max(dp[u][dep], sum);
            }
        }
        for (int i = k - 1; i >= 0; i--) dp[u][i] = max(dp[u][i], dp[u][i + 1]);
    }
    int main() {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
        for (int i = 2; i <= n; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
        dfs(1, -1);
        printf("%d\n", dp[1][0]);
        return 0;
    }
    View Code

    官方题解里vector太多了,看的好懵逼。提交最后解释了一下为什么复杂度是O(n^3)不是O(n^4),但是我看着还是感觉复杂度是O(n^4)

——————————————————————————————————————————————————————————————

第一次把一场CF所有题都补出来,开心

posted @ 2019-10-24 15:06  Angel&Demon  阅读(...)  评论(... 编辑 收藏