Codeforces Round #565 (Div. 3)

http://codeforces.com/contest/1176

ABCDEF
1A1A1Aafter the game by tutorialafter the game by myselfafter the game by myself

\(rank:1097\) (赛中有点事,精神恍惚去了233)

A

由题可知,分别消掉\(1\)\(2,3,5\)分别需要\(1,2,3\)的花费,于是我们算出\(n\)中包含的\(2,3,5\)的个数就好

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
int q;
ll m;
int main() {
    cin >> q;
    while (q--) {
        cin >> m;
        int a = 0, b = 0, c = 0;
        while (m % 2 == 0) {
            a++; m /= 2;
        }
        while (m % 3 == 0) {
            b++; m /= 3;
        }
        while (m % 5 == 0) {
            c++; m /= 5;
        }
        if (m == 1)cout << a + b * 2 + c * 3 << '\n';
        else cout << "-1\n";
    }
    return 0;
}

B

\(a_i\)\(3\)取模,记\(cnt[x]=x\)的数量,则\(ans\)=\(cnt[0] + min(cnt[1],cnt[2]) + \lfloor \frac{max(cnt[1],cnt[2])-min(cnt[1],cnt[2])}{3}\rfloor\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
int t, n, a, cnt[3];

int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        for (int i = 0; i < 3; i++)cnt[i] = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a;
            cnt[a % 3]++;
        }
        if (cnt[1] > cnt[2])swap(cnt[1], cnt[2]); cnt[2] -= cnt[1];
        int ans = cnt[0] + cnt[1] + cnt[2] / 3;
        cout << ans << '\n';
    }
    return 0;
}

C

记原序列中 \(subsequences\) \(4,8,15,16,23,42\)的数量为\(m\),则答案为\[n-6*m\]

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
int n, a;
int mp[100], cnt[7];
int main() {
    mp[4] = 1; mp[8] = 2; mp[15] = 3; mp[16] = 4; mp[23] = 5; mp[42] = 6;
    cin >> n;
    cnt[0] = 5e5 + 5;
    for (int i = 1; i <= n; i++) {
        cin >> a;
        a = mp[a];
        if (cnt[a - 1]) {
            cnt[a - 1]--; cnt[a]++;
        }
    }
    cout << n - cnt[6] * 6 << '\n';
    return 0;
}

D

一个很明显的想法即是从大到小贪心,因为当前最大的一个一定要和前面的某个进行配对。
记当前数为\(x\)\(mp[x]\)= \(\{k:The\ k^{th}\ prime\ is\ x\}\),\(low[x] = x\)的最小素因子
如果\(x\)为素数,则把\(mp[x]\)加入答案。
否则,把\(x\)加入答案。
具体实现用一个\(multiset\)每次从最大的,然后删除当前以及匹配的那个。\(mp\)\(low\)都可以通过线筛\(O(n)\)搞定

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2750131 + 5, BOUND = 2750131;
typedef long long ll;
int n, x, primes[MAXN], cnt, low[MAXN], mp[MAXN];
bool is_prime[MAXN];
vector<int> ans;
multiset<int> st;
void init() {
    is_prime[1] = 1;
    for (int i = 2; i <= BOUND; i++) {
        if (!is_prime[i])primes[++cnt] = i;
        for (int j = 1; j <= cnt && primes[j] * i <= BOUND; j++) {
            is_prime[i*primes[j]] = 1; low[i*primes[j]] = primes[j];
            if (i%primes[j] == 0) {
                break;
            }
        }
    }
    for (int i = 1; i <= cnt; i++) {
        mp[primes[i]] = i;
    }
}
int main() {
    init();
    cin >> n;
    for (int i = 1; i <= n * 2; i++) {
        cin >> x;
        st.insert(x);
    }
    while (st.size()) {
        int x = *st.rbegin();
        st.erase(--st.end());
        if (is_prime[x]) {
            auto it = st.find(x / low[x]);
            ans.push_back(x); st.erase(it);
        }
        else {
            int t = mp[x];
            auto it = st.find(t);
            ans.push_back(t); st.erase(it);
        }
    }
    for (int i = 0; i < ans.size(); i++) {
        cout << ans[i] << " \n"[i == ans.size() - 1];
    }
    return 0;
}

E

最多选\(\lfloor \frac{n}{2} \rfloor\)个,所以我们直接遍历一遍图,对图进行黑白染色,然后输出颜色比较少的点就好,可以证明这样一定点数少于等于\(\lfloor \frac{n}{2} \rfloor\),并且满足题设条件

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
int t, n, m, u, v;
bool vis[MAXN];
vector<int > ans, G[MAXN];
void dfs(int u, int f, int d) {
    vis[u] = 1;
    if (d == 1)ans.push_back(u);
    for (int v : G[u]) {
        if (vis[v])continue;
        dfs(v, u, d ^ 1);
    }
}
int main() {
    cin >> t;
    while (t--) {
        cin >> n >> m;
        for (int i = 1; i <= n; i++)G[i].clear();
        ans.clear();
        for (int i = 1; i <= m; i++) {
            cin >> u >> v;
            G[u].push_back(v); G[v].push_back(u);
        }
        for (int i = 1; i <= n; i++)vis[i] = 0;
        dfs(1, 0, 0);
        if (ans.size() <= n / 2) {
            cout << ans.size() << '\n';
            for (int i = 0; i < ans.size(); i++) {
                cout << ans[i] << " \n"[i == ans.size() - 1];
            }
        }
        else {
            for (int i = 1; i <= n; i++)vis[i] = 0;
            ans.clear();
            dfs(1, 0, 1);
            cout << ans.size() << '\n';
            for (int i = 0; i < ans.size(); i++) {
                cout << ans[i] << " \n"[i == ans.size() - 1];
            }
        }
    }
    return 0;
}

F

简单\(dp\)。定义\(dp[i][x]\)\(i\)为当前的\(turn\)\(x\)为当前选了多少张牌,由题,我们只关心 \(x\bmod10\)的值,以此来判断什么是否\(double\ damage\),然后转移就好。细节处理看代码。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5, BOUND = 2750131;
typedef long long ll;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
int n, x, c, d, mx[4], v[MAXN][6];
ll dp[MAXN][12];
priority_queue<int, vector<int>, greater<int>> s;
inline int calc(int j, int k) {
    return j - k < 0;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> x;
        memset(mx, 0, sizeof(mx));
        for (int j = 1; j <= x; j++) {
            cin >> c >> d;
            if (c == 1) {
                s.push(d);
                if (s.size() > 3)s.pop();
            }
            else {
                mx[c] = max(mx[c], d);
            }
        }
        int y = 3 - s.size() + 1;
        while (s.size()) {
            v[i][y++] = s.top(); s.pop();
        }
        v[i][4] = mx[2]; v[i][5] = mx[3];
    }
    for (int i = 0; i < 10; i++)dp[0][i] = -INFL;
    dp[0][0] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < 10; j++) {
            dp[i][j] = dp[i - 1][j];
            if (v[i][5])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + v[i][5] * calc(j, 1) + v[i][5]);
            if (v[i][4])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + v[i][4] * calc(j, 1) + v[i][4]);
            if (v[i][3])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + v[i][3] * calc(j, 1) + v[i][3]);
            if (v[i][4] && v[i][3])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + v[i][4] + v[i][3] + max(v[i][4], v[i][3])*calc(j, 2));
            if (v[i][3] && v[i][2])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + v[i][2] + v[i][3] + max(v[i][2], v[i][3])*calc(j, 2));
            if (v[i][3] && v[i][2] && v[i][1])dp[i][j] = max(dp[i][j], dp[i - 1][(j - 3 + 10) % 10] + v[i][3] + v[i][2] + v[i][1] + max(v[i][1], max(v[i][2], v[i][3]))*calc(j, 3));
        }
    }
    ll ans = 0;
    for (int i = 0; i < 10; i++)ans = max(ans, dp[n][i]);
    cout << ans << '\n';
    return 0;
}

转载于:https://www.cnblogs.com/sienna/p/11001986.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值