zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 190 E/F

    上号之后看了眼F,发现巨水就顺手写了这场比赛。

    E-Magical Ornament

    思路

    注意到k很小,从这边入手,可以发现最终的答案就是这k个点的哈密顿路径。那么先跑一遍k次的最短路预处理出距离,然后拿状压dp跑一遍就好。

    dp[i][j]表示状态为i,到达j点的最小代价。具体转移方程看代码。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const int N = 1e5 + 10;
    vector<int> e[N];
    int a[N];
    int f[20][20], dis[N], k, res;
    bool st[N];
    int dp[(1 << 20)][20];
    
    void dijkstra(int s, int idx) {
        memset(st, 0, sizeof st);
        memset(dis, 0x3f, sizeof dis);
        dis[s] = 0;
        priority_queue<PII, vector<PII>, greater<PII> > q;
        q.push({0, s});
        while(!q.empty()) {
            int u = q.top().second; q.pop();
            if(st[u]) continue;
            st[u] = true;
            for(auto v : e[u]) {
                if(dis[v] > dis[u] + 1) {
                    dis[v] = dis[u] + 1;
                    q.push({dis[v], v});
                }
            }
        }
        for(int i = 1; i <= k; i++) {
            f[idx][i] = dis[a[i]];
        }
    }
    
    void solve() {
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            e[u].push_back(v);
            e[v].push_back(u);
        }
        scanf("%d", &k);
        for(int i = 1; i <= k; i++) {
            scanf("%d", &a[i]);
        }
        for(int i = 1; i <= k; i++) {
            dijkstra(a[i], i);
        }
        memset(dp, 0x3f, sizeof dp);
        for(int i = 0; i < k; i++) {
            dp[(1 << i)][i] = 0;
            // cout << (1 << i) << endl;
        }
    
        for(int i = 0; i < (1 << k); i++) {
            for(int u = 0; u < k; u++) {
                if((i >> u) & 1) {
                    for(int v = 0; v < k; v++) {
                        if(!((i >> v) & 1)) {
                            dp[i + (1 << v)][v] = min(dp[i + (1 << v)][v], dp[i][u] + f[u + 1][v + 1]);
                        }
                    }
                }
            }
        }
        int res = 1e9;
        for(int i = 0; i < k; i++) {
            res = min(res, dp[(1 << k) - 1][i]);
        }
        if(res == 1e9) res = -2;
        printf("%d
    ", res + 1);
    
    }
    
    int main() {
        // freopen("in.txt", "r", stdin);
        solve();
        return 0;
    }
    

    F-Shift and Inversions

    思路

    可以发现对于每个k,其实就是把当前第一位数移到最后一位,若当前数为x,如果把x从序列中拿走,会减少x-1个逆序对。把x插入到最后一位序列上,会增加n-x个逆序对。那么先解决给定数组的逆序对数,然后O(n)跑一遍即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 3e5 + 10;
    LL tr[N];
    int n, a[N];
    
    int lowbit(int x) {
        return x & -x;
    }
    
    void add(int x, int val) {
        for(int i = x; i <= n; i += lowbit(i)) {
            tr[i] += val;
        }
    }
    
    LL sum(int x) {
        LL res = 0;
        for(int i = x; i > 0; i -= lowbit(i)) {
            res += tr[i];
        }
        return res;
    }
    
    void solve() {
        scanf("%d", &n);
        LL res = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            a[i]++;
        }
        for(int i = n; i >= 1; i--) {
            res += sum(a[i] - 1);
            add(a[i], 1);
        }
        printf("%lld
    ", res);
        for(int i = 1; i < n; i++) {
            res -= a[i] - 1;
            res += n - a[i];
            printf("%lld
    ", res);
        }
    }
    
    int main() {
        // freopen("in.txt", "r", stdin);
        solve();
        return 0;
    }
    
  • 相关阅读:
    Day Six(Beta)
    Day Five (beta)
    Day Four(Beta)
    Day Three(Beta)
    Day Two(Beta)
    Day One(Beta)
    项目冲刺——总结
    beta版本贡献率
    软件工程实践总结
    团队作业--Beta版本冲刺
  • 原文地址:https://www.cnblogs.com/ZX-GO/p/14351715.html
Copyright © 2011-2022 走看看