zoukankan      html  css  js  c++  java
  • 牛客网暑期多校2

    B - discount

    题目大意:有n种饮料,每种饮料的价格为p[ i ]。

    购买第 i 种饮料的时候,你可以在一下两种优惠中选择一种:

    1:该饮料优惠d[ i ]元

    2:免费送一瓶第f[ i ]种饮料

    问最少花费多少钱使得每种饮料至少都有一瓶。

    思路:最后组成一个基环内向图,先考虑树上的情况,我们设

    dp[ i ][ 0 ]表示以 i 为子树的全部饮料至少有一瓶的最少花费

    dp[ i ][ 1 ]表示以 i 为子树的全部饮料至少有一瓶的最少花费,并且第 i 中饮料用了第二种优惠

    这样树上的就很容易dp出来。(dp的时候把环上的边都断开)

    然后对环进行dp,我们随便选一条边断开,让它成为一条线段,然后在线段上进行dp,因为原来是环,

    我们需要枚举初始位置的状态,即第一个点受不受最后一个点的影响。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define pii pair<int, int>
    #define y1 skldjfskldjg
    #define y2 skldfjsklejg
    
    using namespace std;
    
    const int N = 1e5 + 7;
    const int M = 1e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 +7;
    
    int n, tot, top, m, p[N], d[N], f[N], head[N], stk[N];
    int vis[N];
    bool is[N];
    LL dp[N][2], DP[N][2], sum[N];
    vector<int> cir[N];
    
    struct Edge {
        int to, nx;
    } edge[N << 1];
    
    void add(int u, int v) {
        edge[tot].to = v;
        edge[tot].nx = head[u];
        head[u] = tot++;
    }
    
    
    void getCir(int u) {
        vis[u] = -1;
        stk[++top] = u;
    
        int nx = f[u];
    
        if(vis[nx] == 0) {
            getCir(nx);
        } else if(vis[nx] == -1) {
            m++;
            for(int i = top; i >= 1; i--) {
                cir[m].push_back(stk[i]);
                is[stk[i]] = true;
                if(stk[i] == nx) break;
            }
            reverse(cir[m].begin(), cir[m].end());
        }
    
        top--;
        vis[u] = 1;
    }
    
    void dfs(int u) {
        for(int i = head[u]; ~i; i = edge[i].nx) {
            int v = edge[i].to;
            if(is[v]) continue;
            dfs(v);
            sum[u] += dp[v][0];
        }
    
        dp[u][1] = p[u] + sum[u];
        dp[u][0] = p[u] - d[u] + sum[u];
    
        for(int i = head[u]; ~i; i = edge[i].nx) {
            int v = edge[i].to;
            if(is[v]) continue;
            dp[u][0] = min(dp[u][0], sum[u] - dp[v][0] + dp[v][1]);
        }
    }
    
    int main() {
        memset(head, -1, sizeof(head));
        scanf("%d", &n);
    
        for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
        for(int i = 1; i <= n; i++) scanf("%d", &d[i]);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &f[i]);
            add(f[i], i);
        }
    
        for(int i = 1; i <= n; i++) {
            if(!vis[i]) {
                top = 0;
                getCir(i);
            }
        }
    
        LL ans = 0;
    
        for(int i = 1; i <= m; i++) {
            for(int j = 0; j < cir[i].size(); j++) {
                int root = cir[i][j];
                dfs(root);
            }
    
            LL tmp = INF;
            DP[0][0] = dp[cir[i][0]][0]; DP[0][1] = dp[cir[i][0]][1];
            for(int j = 1; j < cir[i].size(); j++) {
                int id = cir[i][j];
                DP[j][0] = DP[j - 1][0] + dp[id][0];
                DP[j][0] = min(DP[j][0], DP[j - 1][1] + sum[id]);
                DP[j][1] = DP[j - 1][0] + sum[id] + p[id];
            }
    
    
            tmp = min(tmp, DP[cir[i].size() - 1][0]);
    
    
            DP[0][0] = sum[cir[i][0]]; DP[0][1] = dp[cir[i][0]][1];
            for(int j = 1; j < cir[i].size(); j++) {
                int id = cir[i][j];
                DP[j][0] = DP[j - 1][0] + dp[id][0];
                DP[j][0] = min(DP[j][0], DP[j - 1][1] + sum[id]);
                DP[j][1] = DP[j - 1][0] + sum[id] + p[id];
            }
    
            tmp = min(tmp, DP[cir[i].size() - 1][1]);
            ans += tmp;
        }
    
        printf("%lld
    ", ans);
        return 0;
    }
    
    
    /*
    */
    View Code

      

  • 相关阅读:
    Oracle 冷备份详解【实战案例】
    Oracle Procedure记录
    【基础操作】1.表操作
    Oracle的基本语法,存储函数及触发器
    有志者事竟成 — 雷林鹏
    Les13 性能管理
    SharePoint 2010 创建联系人列表和使用联系人列表
    在SharePoint 2010中创建联系人Web数据库网站
    C#中数组如何赋值
    What Can Happen When You Try to Convert a Standard SharePoint 2010 Farm to Enterprise
  • 原文地址:https://www.cnblogs.com/CJLHY/p/9362272.html
Copyright © 2011-2022 走看看