ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021 CCPC 女生赛

2021-11-06 21:03:51  阅读:192  来源: 互联网

标签:now 女生 int CCPC st ++ 2021 include dp


前两周都没怎么训练呜呜,作业太多了
http://codeforces.com/gym/103389

5道签到题就不放code了毕竟打完找不着了

C 连锁商店

状压DP,场上只能想到 \(O(2^n n^2)\)的做法,还觉得他卡不满,T了一发发现完全图就直接爆炸了。然后也不会优化,后来学到两种处理方式。

一种是题解的做法,将点分类讨论,对于只出现一次的商店不需要存入状态,而出现大于一次的商店总数不超过 \(n/2\),这样的做法是 \(O(2^{n/2} n^2)\)

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <vector>
typedef long long ll;
#define endl '\n'
#define P pair<int, int>
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0);
using namespace std;
const int N = 37;
const int INF = 0x3f3f3f3f;
#define int ll
vector<int> mp[N];
map<int, int> dp[N];

int cnt[N];
int n, m, c[N], w[N], cid[N];
signed main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> c[i], c[i]--, cnt[c[i]]++;
    for (int i = 0; i < n; i++) cin >> w[i];
    for (int i = 0, u, v; i < m; i++) {
        cin >> u >> v;
        mp[u].push_back(v);
    }

    int sn = 0;
    for (int i = 0; i < n; i++) {
        if (cnt[i] > 1) {
            cid[i] = sn++;
        }
    }

    if (cnt[c[1]] > 1) {
        dp[1][1 << cid[c[1]]] = w[c[1]];
    } else {
        dp[1][0] = w[c[1]];
    }
    for (int u = 1; u <= n; u++) {
        for (auto v : mp[u]) {
            if (cnt[c[v]] <= 1) {
                for (auto st : dp[u]) {
                    ll now = st.first;
                    dp[v][now] = max(dp[v][now], dp[u][now] + w[c[v]]);
                }
            } else {
                for (auto st : dp[u]) {
                    int now = st.first;
                    int id = cid[c[v]];
                    // bitset<5> a(now);
                    // cout << u << ": " << v << " " << c[v] << "|" << id << " "
                    //      << a << endl;
                    if ((now >> id) & 1) {
                        dp[v][now] = max(dp[v][now], dp[u][now]);
                    } else {
                        dp[v][now | (1 << id)] =
                            max(dp[v][now | (1 << id)], dp[u][now] + w[c[v]]);
                    }
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        int res = 0;
        for (auto st : dp[i]) {
            res = max(res, st.second);
        }
        cout << res << endl;
    }
}

另一种是很符合直觉的做法,很好想,但是我不会算复杂度。
注意到一个状态的所有子集一定没有它本身优,即 \(10110\) 最后的答案一定比 \(10111\) 要劣,所以可以每转移完一个点就将无用状态剔除一遍,具体操作就是这样

//处理st[now]
void del(int now) {
    vector<ll> tmp;
    for (int i = 0; i < st[now].size(); i++) {
        bool flag = 1;
        for (int j = 0; j < st[now].size(); j++) {
            if (i == j) continue;
            if ((st[now][i] | st[now][j]) == st[now][j]) {//如果i是任何一个集合的子集,则剔除
                flag = 0;
                break;
            }
        }
        if (flag) tmp.push_back(st[now][i]);
    }
    st[now] = tmp;
}

标签:now,女生,int,CCPC,st,++,2021,include,dp
来源: https://www.cnblogs.com/FushimiYuki/p/15518339.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有