• Bzoj1495: [NOI2006]网络收费


    题面

    传送门

    Sol

    把每个节点都加上(2^n-1)
    那么非叶节点的编号就是(1)(2^n-1)
    就可以把它当成是一棵线段树了

    然后看收费的方法
    意思就是(A)多就收(A)
    否则收(B)的费用

    可以处理出每个叶节点经过某个(LCA)的费用和
    那么枚举这条链上的非叶节点的(A)是否大于(B)就可以算出要收的费用了

    然后设(f[i][j])表示(i)号点,观察到的叶节点选了(j)(A)的最小代价
    假如枚举的是(A>B)那么背包转移时,要保证(j)大于区间长度的一半
    否则
    要保证小于一半

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    const int _(2050);
    const int INF(1e9);
    typedef long long ll;
    
    IL int Input(){
        RG int x = 0, z = 1; RG char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    int n, pw[11], a[_], c[_], cost[_][_], f[_][_], ans = 2e9, cp[_];
    
    IL int LCA(RG int x, RG int y){
    	while(x != y) x = x >> 1, y = y >> 1;
    	return x;
    }
    
    IL void Solve(RG int p, RG int d){
    	if(!d){
    		f[p][a[p]] = 0, f[p][a[p] ^ 1] = c[p];
    		for(RG int i = p >> 1; i; i >>= 1) f[p][cp[i]] += cost[i][p];
    		return;
    	}
    	for(RG int i = 0; i <= pw[n]; ++i) f[p][i] = INF;
    	cp[p] = 0, Solve(p << 1, d - 1), Solve(p << 1 | 1, d - 1);
    	for(RG int i = 1; i <= pw[d - 1]; ++i)
    		for(RG int j = pw[d - 1] - i + 1; i + j <= pw[d]; ++j)
    			f[p][i + j] = min(f[p][i + j], f[p << 1][i] + f[p << 1 | 1][j]);
    	cp[p] = 1, Solve(p << 1, d - 1), Solve(p << 1 | 1, d - 1);
    	for(RG int i = 0; i <= pw[d - 1]; ++i)
    		for(RG int j = 0; i + j <= pw[d - 1]; ++j)
    			f[p][i + j] = min(f[p][i + j], f[p << 1][i] + f[p << 1 | 1][j]);
    }
    
    int main(RG int argc, RG char* argv[]){
    	n = Input(), pw[0] = 1;
    	for(RG int i = 1; i <= 10; ++i) pw[i] = pw[i - 1] << 1;
    	for(RG int i = 1; i <= pw[n]; ++i) a[pw[n] + i - 1] = Input();
    	for(RG int i = 1; i <= pw[n]; ++i) c[pw[n] + i - 1] = Input();
    	for(RG int i = 1; i < pw[n]; ++i)
    		for(RG int j = i + 1; j <= pw[n]; ++j){
    			RG int x = i + pw[n] - 1, y = j + pw[n] - 1;
    			RG int v = Input(), d = LCA(x, y);
    			cost[d][x] += v, cost[d][y] += v;
    		}
    	Solve(1, n);
    	for(RG int i = 0; i <= pw[n]; ++i) ans = min(ans, f[1][i]);
    	printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    子树的结点个数
    CF988 D. Points and Powers of Two【hash/数学推理】
    回溯法练习【BFS/DFS】
    Zoj 1610 Count the Colors (线段树+区间更新+暴力计数)
    Poj 2947 widget factory (高斯消元解同模方程)
    Poj 2065 SETI (高斯消元)
    Lightoj 1054
    Poj 2528 Mayor's posters (线段树+离散化)
    Lightoj 1090
    Poj 1753 Flip Game 高斯消元
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8714505.html
Copyright © 2020-2023  润新知