Codeforces Round #697 (Div. 3) A~E题解

写在前边

状态及其不佳,很累很困,还好\(unrated\)

链接:Codeforces Round #697 (Div. 3)

A. Odd Divisor

链接:A题链接

题目大意:

判断一个数是否有奇数因子。

思路

一开始挺懵的,然后自己推了一下,发现只有\(2\)的幂才不会有奇数因子,因此本题只需要判断是否是二的幂即可,利用位运算,\(x \& (x - 1)\)

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <cmath>

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define PLL pair<long, long>

typedef long long ll;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

void solve() {
    ll n;
    cin >> n;
    if (n & (n - 1)) {
        puts("YES");
    } else {
        puts("NO");
    }
}

int main()
{
    ios::sync_with_stdio(false), cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
} 

B. New Year's Number

链接:B题链接

题目大意:

判断一个数\(n\)是否可以由\(a\)\(2021\)\(b\)\(2020\)组成。

思路

既然由\(2020\)\(2021\)组成,那么只需要判断\(n\)\(2020\)取模后得到的数是否可以由\(n / 2020\)\(1\)组成即可,即\((n \% 2020) <= (n / 2020)\)

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define PLL pair<long, long>

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

void solve() {
    int n;
    cin >> n;
    if ((n % 2020) <= (n / 2020)) {
        puts("YES");
    } else {
        puts("NO");
    }
}

int main()
{
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

C. Ball in Berland

链接:C题链接

题目大意:

\(a\)个男生,\(b\)个女生,一个男生一个女生组合起来跳舞,并且要求选出两对,给出\(k\)对男女组合,求有多少种组合方式。

思路

可以两重直接循环枚举,枚举到\([a, b]\)的时候,二重循环中判断不包含\(a,b\)顶点的都可以加到答案中,但是直接枚举肯定超时,因此优化一下我们就可以预处理出\(a\)的出度\(degreeA[a]\)\(b\)的出度\(degreeB[b]\),那么一重循环枚举到\([a, b]\)我们可以直接找到不符合条件的有几个,即\(degreeA[a] + degreeB[b] - 1\),一共有\(k\)对那么符合条件的就有\(k - (degreeA[a] + degreeB[b] - 1)\),因此就从\(O(n^2)\)优化到了\(O(n)\),最后再将答案除以\(2\)即可,因为每个顶点都算了两遍。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define PLL pair<long, long>

typedef long long ll;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int N = 2e5 + 10;
int edga[N], edgb[N];
ll out_degreeA[N], out_degreeB[N];

void solve() {
    int a, b, k;
    cin >> a >> b >> k;
    for (int i = 1; i <= k; i++) {
        cin >> edga[i];
        out_degreeA[edga[i]]++;
    }
    for (int i = 1; i <= k; i++) {
        cin >> edgb[i];
        out_degreeB[edgb[i]]++;
    }
    ll res = 0;
    for (int i = 1; i <= k; i++) {
        res += k - (out_degreeA[edga[i]] + out_degreeB[edgb[i]] - 1);
    }
    cout << res / 2 << endl;
    memset(out_degreeA, 0, sizeof out_degreeA);
    memset(out_degreeB, 0, sizeof out_degreeB);
}

int main()
{
    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
} 

D. Cleaning the Phone

链接:D题链接

题目大意:

清理手机问题,每个\(app\)占用内存\(a_i\),它相应的实用度有\(b_i\) \((b_i只能为1或2)\),那么总的实用度就是\(b_i\)的和,现在要清理内存,要求清理出至少\(m\)的内存,损失最少实用度,求出损失的最少实用度,若没有则输出\(-1\)

思路

很明显的贪心策略就是优先删除实用度为\(1\)并且占内存比较大的,再者就是删除实用度为\(2\)占内存比较大的,而但是毕竟选择的不是一两个\(app\),因此为了解决这个问题可以将实用度为1或者2的分成两个数组,然后求其前缀和,最好的方案就是再能达到需求的情况下尽可能少的卸载实用度为\(2\)\(app\),因此从大到小枚举实用度为\(2\)\(app\),然后剩下就是\(m - preSum2\),那么另一边就用二分来选择\(preSum1\),维护一个\(res\)始终为最小方案。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <climits>

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define PLL pair<long, long>

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

void solve() {
    int n, m;
    cin >> n >> m;
    vector<LL> v(n + 1), preSum1, preSum2;
    preSum1.push_back(0), preSum2.push_back(0);
    for (int i = 1; i <= n; i++) {
        cin >> v[i];
    }
    for (int i = 1; i <= n; i++) {
        int c;
        cin >> c;
        if (c == 1) {
            preSum1.push_back(v[i]);
        }
        else if (c == 2) {
            preSum2.push_back(v[i]);
        }
    }

    sort(preSum2.rbegin(), preSum2.rend() - 1), sort(preSum1.rbegin(), preSum1.rend() - 1);
    
    for (int i = 1; i < preSum1.size(); i++) {
        preSum1[i] += preSum1[i - 1];
    }
    for (int i = 1; i < preSum2.size(); i++) {
        preSum2[i] += preSum2[i - 1];
    }

    LL res = INT_MAX;
    for (int i = preSum2.size() - 1; i >= 0; i--) { //从大到小枚举
        LL aim = m - preSum2[i];
        LL l = 0, r = preSum1.size(); 
        while (l < r) {
             LL mid = l + r >> 1;
            if (preSum1[mid] >= aim) {
                res = min(res, i * 2 + mid);
                r = mid;
            }
            else {
                l = mid + 1;
            }
        }
    }
    cout << (res == INT_MAX ? -1 : res) << endl;
}

int main()
{
    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

E. Advertising Agency

链接:E题链接

题目大意:

一个人从\(n\)个博主里选\(k\)个来带货,那么她当然是优先选择粉丝多的博主了,问有多少种选择方案。

思路

\(cnt[x]\)为拥有\(x\)个粉丝的博主,那么我们肯定优先从粉丝多的博主选了,例如要求选\(k\)个,已经选了\(m\)个,还剩下\(k - m\)个需要选,那么现在\(cnt[x] >= k - m\),因此只需要从cnt[x]里选k-m个即可,即求组合数,因为数据范围很小,可以直接用递推式即可:\(C_a^b = C_{a-1}^{b} + C_{a-1}^{b-1}\)

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>

using namespace std;

#define Inf 0x3f3f3f3f
#define PII pair<int, int>
#define PLL pair<long, long>

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<long long> VLL;
typedef vector<int> VI;

const int mod = 1e9 + 7;
const int N = 1010;
int c[N][N];

void init() {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j <= i; j++) {
            if (!j) {
                c[i][j] = 1;
            } else {
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
            }
        }
    }
}

void solve() {
    int k, n;
    cin >> n >> k;
    vector<int> cnt(n + 1);
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        cnt[x]++;
    }   
    init();
    for (int i = n; i >= 1; i--) {
        if (cnt[i] >= k) {
            cout << c[cnt[i]][k] << endl;
            return;
        } else {
            k -= cnt[i];
        }
    }
}

int main()
{
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
posted @ 2021-01-27 18:37  Xxaj5  阅读(87)  评论(0编辑  收藏  举报