• [BZOJ4007][JLOI2015]战争调度


    题目描述

    脸哥最近来到了一个神奇的王国,王国里的公民每个公民有两个下属或者没有下属,这种关系刚好组成一个 (n) 层的完全二叉树。

    公民 (i) 的下属是 (2 * i)(2 * i +1)。最下层的公民即叶子节点的公民是平民,平民没有下属,最上层的是国王,中间是各级贵族。

    现在这个王国爆发了战争,国王需要决定每一个平民是去种地以供应粮食还是参加战争,每一个贵族(包括国王自己)是去管理后勤还是领兵打仗。

    一个平民会对他的所有直系上司有贡献度,若一个平民$ i$参加战争,他的某个直系上司 (j) 领兵打仗,那么这个平民对上司的作战贡献度为 (w_{i,j})

    若一个平民(i) 种地,他的某个直系上司$ j$ 管理后勤,那么这个平民对上司的后勤贡献度为 (f_{i,j}),若 (i)(j) 所参加的事务不同,则没有贡献度。

    为了战争需要保障后勤,国王还要求不多于 (m) 个平民参加战争。国王想要使整个王国所有贵族得到的贡献度最大,并把这件事交给了脸哥。但不幸的是,脸哥还有很多 (deadline) 没有完成,他只能把这件事又转交给你。你能帮他安排吗?

    Input

    第一行两个数 (n,m)

    接下来 (2^{n-1}) 行,每行(n-1) 个数,第 (i) 行表示编号为 (2^{n-1}-1+ i) 的平民对其(n-1)直系上司的作战贡献度,其中第一个数表示对第一级直系上司,即编号为 ((2^{n-1}-1+ i)/2) 的贵族的作战贡献度 (w_{i,j}),依次往上。

    接下来 (2^{n-1})行,每行(n-1)个数,第i行表示编号为 (2^{n-1}-1+ i)的平民对其(n-1)个直系上司的后勤贡献度,其中第一个数表示对第一级直系上司,即编号为 (2^{n-1}-1+ i)/2) 的贵族的后勤贡献度 (f_{i,j}) ,依次往上。

    对于 (100\%) 的数据,(2 <= n <= 10,m <= 2n 1,0 <= w_{i,j} ,f_{i,j} <= 2000)

    Output

    包括一个非负整数,表示有多少种放置的方案.

    Sample Input

    3 4
    503 1082
    1271 369
    303 1135
    749 1289
    100 54
    837 826
    947 699
    216 389
    

    Sample Output

    6701
    

    一道(dp)优化搜索,雾(什么东西)

    那么小的范围随便乱搞就好了。。。

    首先,我们发现这道题的数据范围及其的小!!!!

    我们只用暴力搜出所有的贵族做哪些工作就可以了。

    对于一个叶子节点,我们枚举它所有的父亲节点,然后进行(dp)转移。

    若当前父亲打仗,(dp[x][1]+=W[i,j]),否则,(dp[x][0]+=F[i,j])

    于是,对于一个节点我们可以将其两个子节点进行合并,一个类似于背包的转移。

    ret(i,0,1<<y-1)ret(j,0,1<<y-1)Max(dp[x][i+j],dp[x<<1][i]+dp[x<<1|1][j]);
    

    注意,每次搜一个节点前都要清空当前dp数组

    #include <bits/stdc++.h>
     
    using namespace std;
     
    #define int long long
    #define reg register
    #define Raed Read
    #define clr(a,b) memset(a,b,sizeof a)
    #define Mod(x) (x>=mod)&&(x-=mod)
    #define debug(x) cerr<<#x<<" = "<<x<<endl;
    #define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
    #define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
    #define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
    #define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
     
    inline int Read(void) {
        int res=0,f=1;
        char c;
        while(c=getchar(),c<48||c>57)if(c=='-')f=0;
        do res=(res<<3)+(res<<1)+(c^48);
        while(c=getchar(),c>=48&&c<=57);
        return f?res:-res;
    }
     
    template<class T>inline bool Min(T &a, T const&b) {
        return a>b?a=b,1:0;
    }
    template<class T>inline bool Max(T &a, T const&b) {
        return a<b?a=b,1:0;
    }
    const int N=15,M=1e5+5;
     
    bool MOP1;
     
    int n,m,Pow[N],W[(1<<10)+5][15],F[(1<<10)+5][15],dp[(1<<10)+5][(1<<10)+5],vis[15];
     
    void dfs(int x,int y) {
        ret(i,0,1<<y)dp[x][i]=0;
        if(y==1) {
            rep(i,2,n)if(vis[i])dp[x][1]+=W[x][i-1];
            else dp[x][0]+=F[x][i-1];
            return;
        }
        vis[y]=0,dfs(x<<1,y-1),dfs(x<<1|1,y-1);
        ret(i,0,1<<y-1)ret(j,0,1<<y-1)Max(dp[x][i+j],dp[x<<1][i]+dp[x<<1|1][j]);
        vis[y]=1,dfs(x<<1,y-1),dfs(x<<1|1,y-1);
        ret(i,0,1<<y-1)ret(j,0,1<<y-1)Max(dp[x][i+j],dp[x<<1][i]+dp[x<<1|1][j]);
    }
     
    bool MOP2;
     
    void _main(void) {
        n=Read(),m=Read();
        rep(i,1,1<<n-1)ret(j,1,n)W[(1<<n-1)+i-1][j]=Read();
        rep(i,1,1<<n-1)ret(j,1,n)F[(1<<n-1)+i-1][j]=Read();
        dfs(1,n);
        int Ans=0;
        rep(i,0,m)Max(Ans,dp[1][i]);
        printf("%lld
    ",Ans);
    }
     
    signed main() {
        _main();
    }
    
  • 相关阅读:
    Java 连接 Memcached 服务
    Memcached命令-存储命令-查找命令-清理命令
    memcache安装
    Python爬虫模拟登录带验证码网站
    HashMap原理
    redis 在java中的使用
    redis 事务
    Redis命令续
    Redis命令
    ApplicationListener用法
  • 原文地址:https://www.cnblogs.com/dsjkafdsaf/p/11494507.html
Copyright © 2020-2023  润新知