[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\n",Ans);
}
 
signed main() {
    _main();
}
posted @ 2019-09-09 21:51  dsjkafdsaf  阅读(130)  评论(0编辑  收藏  举报