zoukankan      html  css  js  c++  java
  • P4297 [NOI2006]网络收费 [树形dp]

    网络收费

    点击标题链接查看题目.


    color{blue}{最初想法}

    类似线段树建出一颗树, 暴力枚举每个节点改不改 .


    color{red}{正解部分}

    观察题目的表格, 可以发现:

    • 满足 Na<NbNa < Nb 的子树上, 只有 AA 收费方式需要付费 .
    • 满足 NaNbNa geq Nb 的子树上, 只有 BB 收费方式需要付费 .

    但是此题为两两配对产生贡献,
    直接计算 时间复杂度为 O(N2)O(N^2), 考虑将两个点拆开一个一个去计算 .
    每个 非叶节点 都表示了若干点对的 LCALCA, 结合上方观察得出的结论, 每个节点对答案造成的贡献都可看作在 非叶节点 造成的 .
    则设 cost[i,j]cost[i, j] 表示 ii 这个 叶节点, 在深度为 jj祖先(非叶节点) 中与若干点配对产生的 总流量(费用), 可以 O(N2)O(N^2) 预处理.

    F[i,j]F[i, j] 表示 以 ii 号节点为根的子树, 管辖的叶子节点中含有 jjBB 收费方式叶子节点 的 最小花费,

    F[k,i+j]=min(F[left_soni,i]+F[right_soni,j])       cntb[0,sizei]F[k, i+j]=min(F[left\_son_i, i]+F[right\_son_i,j]) cnt_b∈[0,size_i]

    • Na<NbNa < Nb 需要满足条件 sizeiij<i+jsize_i-i-j<i+j
    • NaNbNa geq Nb 需要满足条件 sizeiiji+jsize_i-i-j geq i+j

    这样往下递归, 每次 假定 当前节点 Na<NbNa<Nb 还是 NaNbNa geq Nb.

    到了叶子节点就可以直接计算这个叶子节点产生的贡献了, 具体地说:

    设当前递归到了 叶子节点 aa,

    • 若当前为 AA 付费方式, 对答案的贡献为 F[a,0]=i=0max_dep!tmp[i]cost[a,i]F[a,0]=sumlimits_{i=0}^{max\_dep} !tmp[i]*cost[a, i] .
    • 若当前为 BB 付费方式, 对答案的贡献为 F[a,1]=i=0max_deptmp[i]cost[a,i]F[a,1]=sumlimits_{i=0}^{max\_dep}tmp[i]*cost[a, i] .

    在上方的 答案统计中, 当且仅当 目前收费方式与 初始收费方式 不同时, 需要加上修改产生的花费 .


    color{red}{实现部分}

    对收费方式的处理: 使用 C[0/1][i]C[0/1][i] 表示第 ii 个用户使用 A/BA/B 收费方式时的 修改 费用, 递归到叶子节点时赋初值 可以方便地处理 修改产生的费用 .

    • tmp[dep]=0tmp[dep] = 0 表示当前 DFSDFS链 中深度为 depdep当前节点 以下 Na<NbNa<Nb, 只有 AA 付费.
    • tmp[dep]=1tmp[dep] = 1 则表示 NaNbNa geq Nb, 只有 BB 付费 .

    求解 LCALCA 深度时, 可以不断 “试” 两个待测节点 x,yx, y, 具体地说:
    不断的对 x,yx, y 执行 >>i>>i 操作, 相当于向上走 ii 步, 当它们走到的节点不同时, 那两个不同的节点的 父亲 即为 LcaLca, 深度为 max_depi1max\_dep-i-1 .


    #include<bits/stdc++.h>
    #define reg register
    typedef long long ll;
    
    const int maxn = 3500;
    
    int n;
    int N;
    int tmp[13];
    int Fs[maxn];
    ll C[2][maxn];
    ll F[maxn][maxn];
    ll cost[maxn][13];
    
    int Lca(int x, int y){
            for(reg int i = n; i >= 0; i --)
            	if((x>>i) != (y>>i)) return n-i-1;
    }
    
    void DFS(int k, int dep, int l, int r){
            if(dep == n){
                    F[k][0] = C[0][l], F[k][1] = C[1][l];
                    for(reg int i = 0; i < dep; i ++) F[k][tmp[i]] += cost[l][i];
                    return ;
            }
    
            int mid = l+r >> 1;
    
    	memset(F[k], 0x3f, sizeof F[k]);
    
            tmp[dep] = 0;
            DFS(k<<1, dep+1, l, mid), DFS(k<<1|1, dep+1, mid+1, r);
            for(reg int i = 0; i <= mid-l+1; i ++)
                    for(reg int j = 0; j <= mid-l+1; j ++){
                    	if(r-l+1-i-j >= i+j) continue ;
    			F[k][i+j] = std::min(F[k][i+j], F[k<<1][i] + F[k<<1|1][j]);
    		}
    
            tmp[dep] = 1;
            DFS(k<<1, dep+1, l, mid), DFS(k<<1|1, dep+1, mid+1, r);
            for(reg int i = 0; i <= mid-l+1; i ++)
                    for(reg int j = 0; j <= mid-l+1; j ++){
                    	if(r-l+1-i-j < i+j) continue ;
    			F[k][i+j] = std::min(F[k][i+j], F[k<<1][i] + F[k<<1|1][j]);
    		}
    }
    
    int main(){
            scanf("%d", &n); N = 1 << n;
            for(reg int i = 1; i <= N; i ++) scanf("%d", &Fs[i]);
            for(reg int i = 1; i <= N; i ++) scanf("%lld", &C[!Fs[i]][i]), C[Fs[i]][i] = 0;
            for(reg int i = 1; i <= N; i ++)
                    for(reg int j = i+1; j <= N; j ++){
                            int x; scanf("%d", &x);
                            int lca_dep = Lca(i-1, j-1);
                            cost[i][lca_dep] += x, cost[j][lca_dep] += x;
                    }
            DFS(1, 0, 1, N);
            ll Ans = 1e18;
            for(reg int i = 0; i <= N; i ++) Ans = std::min(Ans, F[1][i]);
            printf("%lld
    ", Ans);
            return 0;
    }
    
    
  • 相关阅读:
    (C#)asp_net调试错误解决方法收集(1)
    asp.net调试技巧
    asp。Net 页面传值
    viewState详解
    Session,ViewState用法
    asp.net中通过form表单submit提交到后台的实例
    C#读写xml文件
    Asp.Net前台调用后台变量
    3. mybatis # 与 $ 的区别
    IDEA 中 使用 git(Git)
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822541.html
Copyright © 2011-2022 走看看