首页 > 其他分享 >Codeforces Round 961 (Div. 2) 补题记录(A~D)

Codeforces Round 961 (Div. 2) 补题记录(A~D)

时间:2024-07-24 08:58:08浏览次数:20  
标签:log int scanf Codeforces long 2a 补题 lld 961

上大分,赢!

A

考虑将每一条对角线上可以存放的砝码数量都记录一下,从大到小排序,然后直接暴力贪心选择。

此时可以发现数量一定形如 \(n,n-1,n-1,n-2,n-2,n-3,n-3,\ldots,1,1\) 这样的形式。直接暴力减即可。

时间复杂度为 \(O(n)\)。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N];
signed main() {
    int T;
    scanf("%lld", &T);
    while (T--) {
        int n, k;
        scanf("%lld%lld", &n, &k);
        vector<int> v;
        v.emplace_back(n);
        for (int i = n - 1; i; --i) v.emplace_back(i), v.emplace_back(i);
        int cnt = 0;
        int i = 0;
        while (k > 0) {
            k -= v[i];
            ++cnt;
            ++i;
        }
        printf("%lld\n", cnt);
    }
}

B2

B1 做法同 B2。

考虑枚举每一个值 \(i\),计算出其可以选择的最大数目。然后再枚举每一个值 \(i+1\),计算其在选择尽量多 \(i\) 的前提下最大的数目。

然后计算出这个最大的开销,令 \(i\) 值选择了 \(v_1\) 个,\(i+1\) 值还有 \(v_2\) 个没有选择。则可以最多带来 \(\min(v_1,v_2)\) 的收益。所以答案就是 \(\min(m,iv_1+(i+1)v_2+\min(v_1,v_2))\)。

开一个 map 计算出 \(v_1\) 和 \(v_2\) 的最大值即可。时间复杂度为 \(O(n\log n)\)。

还是这张图:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N], b[N];
signed main() {
    int T;
    scanf("%lld", &T);
    while (T--) {
        int n, m;
        scanf("%lld%lld", &n, &m);
        for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
        for (int i = 1; i <= n; ++i) scanf("%lld", &b[i]);
        map<int, int> mp;
        for (int i = 1; i <= n; ++i) mp[a[i]] += b[i];
        sort(a + 1, a + n + 1);
        int mx = 0;
        for (int i = 1; i <= n; ++i) {
            int key = 0;
            int val = a[i];
            int remain = mp[a[i]];
            remain = min(remain, m / val);
            int aix = remain;
            key = a[i] * remain;
            remain = mp[a[i] + 1];
            remain = min(remain, (m - key) / (a[i] + 1));
            key += (a[i] + 1) * remain;
            remain = min(aix, mp[a[i] + 1] - remain);
            key += remain;
            if (key > m) key = m;
            mx = max(mx, key);
        }
        printf("%lld\n", mx);
    }
}

C

首先考虑一下弱化版 CF1883E 的做法。

每一次将一个数乘以 \(2\),很快就会爆 long long 甚至 __uint128。因此考虑一些优美的性质:

  • \(\log_2 2a_i=1+\log_2 a_i\)。

也就是说,可以考虑对于每一个 \(a_i\),都对其取一次 \(\log_2\) 操作。这样一来,问题转化为:

  • 给定一个序列 \(a\),每一次可以将某一个元素 \(+1\),问多少次操作之后序列单调不递减。

这个问题就可以直接贪心的模拟了。

然后考虑本题。本题要求的是对一个数平方。也考虑同样的转化方式:

  • \(\log_2(a_i^2)=2\log_2a_i\)。
  • \(\log_2(2\log_2a_i)=\log_2a_i+\log_22=\log_2a_i+1\)。

也就是说,\(\log_2(\log_2(a_i^2))=\log_2a_i+1\)。对于每一个元素 \(a_i\) 做两遍 \(\log_2\) 就得到的上面简化后的问题。

时间复杂度为 \(O(n)\),注意要使用 long double 否则会被卡精度。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N];
long double b[N];
signed main() {
    int T;
    scanf("%lld", &T);
    while (T--) {
        int n;
        scanf("%lld", &n);
        for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
        bool ok = 1;
        for (int i = 2; i <= n; ++i) if (a[i] < a[i - 1]) ok = 0;
        if (ok) printf("0\n");
        else {
            int pre = 0;
            ok = 1;
            for (int i = 1; i <= n; ++i) {
                pre = max(pre, a[i]);
                if (a[i] == 1) {
                    if (pre > 1) {
                        ok = 0;
                        break;
                    }
                }
            }
            if (!ok) puts("-1");
            else {
                for (int i = 1; i <= n; ++i)
                    b[i] = log2l(log2l(a[i]));
                int cnt = 0;
                for (int i = 2; i <= n; ++i) {
                    if (b[i] < b[i - 1]) {
                        double qwq = b[i - 1] - b[i];
                        int kif = (int)ceill(qwq);
                        cnt += kif;
                        b[i] += kif;
                    }
                }
                printf("%lld\n", cnt);
            }
        }
    }
}

D

考虑 dp。

设 \(f_i\) 表示不存在以集合 \(i\) 结尾的字符,是否是合法的。

那么显然有下列的初始条件:

  • \(f_p=0\),若 \(p\) 为子状态数为 \(1\),且唯一一个子状态为字符串结尾字符。
  • \(f_p=0\),若 \(p\) 状态包含其中一个长度为 \(k\) 的子区间中所有的元素。
  • \(f_p=1\),若 \(p\) 状态同时不满足下列的条件。

但是这显然是错的。因此考虑 dp 更新答案。

按照顺序枚举集合 \(i\in [1,2^c)\)。则有对于任意的一个 \(j\) 满足 \(j\) 是集合 \(i\) 中的一个子元素,\(f_j=f_j\text{ AND }f_{j\oplus2^i}\)。

最终就是在所有满足 \(f_i=0\) 的元素中,找到状态中含有 \(0\) 数量最多的那一个状态就是答案。

时间复杂度为 \(O(c2^c+nc)\)。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 500100;
int a[N], box[N], f[N];
signed main() {
    int T;
    scanf("%lld", &T);
    while (T--) {
        int n, c, k;
        scanf("%lld%lld%lld", &n, &c, &k);
        string s; cin >> s;
        for (int i = 0; i < c; ++i) box[i] = 0;
        for (int i = 0; i < k; ++i) ++box[s[i] - 'A'];
        for (int i = 0; i < (1ll << c); ++i) f[i] = 1;
        f[(1ll << (s[n - 1]) - 'A')] = 0;
        for (int l = 0, r = k - 1; r < n; ++l, ++r) {
            int mask = 0;
            for (int j = 0; j < c; ++j)
                if (box[j]) mask |= (1ll << j);
            f[mask] = 0;
            if (r < n - 1)
                --box[s[l] - 'A'], ++box[s[r + 1] - 'A'];
        }
        for (int i = 1; i < (1ll << c); ++i)
            for (int j = 0; j < c; ++j)
                if (i >> j & 1) f[i] &= f[i ^ (1ll << j)];
        int mi = c;
        for (int i = 1; i < (1ll << c); ++i)
            if (f[i]) mi = min(mi, c - (int)__builtin_popcountll(i));
        printf("%lld\n", mi);
    }
}

标签:log,int,scanf,Codeforces,long,2a,补题,lld,961
From: https://www.cnblogs.com/yhbqwq/p/18320028

相关文章

  • Codeforces 1987C
    codeforcesP1987C给定一个n长度的数组,每一步都要遍历整个数组。如果某个元素是末尾元素或是比其后一个元素大,则该元素减去1直到该元素为0,求解总步数,算法复杂度要求\(O(n)\)先给出暴力解法,复杂度\(O(n^2)\): intt=0; do{ for(inti=0;i<n-1;i++){ if(a[i]......
  • Codeforces Round 957 (Div. 3)复盘
    今天打了一下DIV3,专业转了就是不一样T1Onlypluses这道题主要就是理解乘法分配律,最多的绝对是两数相乘数最大的。T2AngryMonkey这道题一遍AC,虽然很简单还是值得鼓励,主要还是数学问题,用笔写下来找到数学规律之后做起来就很快T3GorillaandPermutation这道题还是很简单......
  • Codeforces Round 952 (Div. 4)复盘
    第一次打比赛的总结Q1CreatingWords这道题其实主要考的就是对于输入语句的理解,最开始我想的是运用scanf,puts,一个语句一个语句的去读取,但是确实对各个输入语句的了解过于肤浅了,特别是哪个读不读空格之类的,其实也算是没有把题目看清楚,它的难度其实没有自己以为的那么难,因为是限......
  • Codeforces 2400+ flows 大杂烩
    CF903GYetAnotherMaxflowProblem2700关键点:最大流转最小割显然我们需要用其他方式维护最大流,考虑到最大流等于最小割,于是我们去求最小割。考虑这个图的特性不难发现左边和右边两列都至多割掉一条边,于是我们直接枚举割掉的位置,剩下的左边前缀和右边后缀所有相连的边都要割......
  • Codeforces Round 960 (Div. 2)
    xht真的好强好强,好厉害这场打得有点史,共四发罚时还是抽象了,如果没有xht就真的完了呜呜。不过也说明我是真的菜,还有把做法想出来之后验证不到位。A.SubmissionBait罚时了,15min才过/lh稍微想一下可以知道,对于最大数\(x\),若其出现次数为奇数,那么A是必胜的,反之则只能从更小......
  • [Codeforces Round 960 (Div. 2)]A-E
    CodeforcesRound960(Div.2)A-EA题意:公平博弈。给定一个数组n个数,每个数只能用一次。给一个\(mx\)。每次轮到自己操作的时候就选一个数组里的数,满足\(a[i]>=mx\),然后令\(mx=a[i]\).双方轮流做直到一方无法操作,则另一方取胜。Sol:赛时1min猜了个错解,只看最大值,只看最大值的出......
  • Codeforces Round 958 (Div. 2)
    Preface周末补题计划的最后一场,这场由于是最古早的所以有些题题意都记不太清了赛时经典发病,前四题一题WA一发,然后把时间打没了E题经典没写完(中间还抽空写了个假做法),邮电部诗人了属于是A.SplittheMultiset刚开始还感觉无从下手,写了个记搜交上去还WA了,后面发现每次分......
  • Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)
    Preface这场比赛的时候CF一直抽风,快10min的时候才登上去,然后中间交题也一直在人机验证50min左右过了前5题后,F没想到生成树当场趋势了,赛后发现原来是原题大战可海星A.DiverseGame将每个数循环移位变为下一个数即可,注意特判\(n=m=1\)的情形#include<cstdio>#incl......
  • Codeforces Round 958 (Div. 2)
    A.SplittheMultisetForexample, {2,2,4} isamultiset.Youhaveamultiset ......
  • Codeforces Round 960 (Div. 2)(A - D)
    CodeforcesRound960(Div.2)(A-D)A-SubmissionBait解题思路:假设直接选最大数,如果最大数有奇数个,\(Alice\)必胜,反之必败。根据这个思路,从大到小看数字,找到第一个出现奇数次的数,从它开始选,就能保证每次\(Alice\)选的时候还剩奇数个选项。代码:#include<bits/stdc++.......