今天一月一号..
突然想安利一波我的中二的2017总结…

传送门1:codevs
传送门2:luogu
时限5s和1s的区别(你没看我传送门都给的大牛分站了)

现在不仅线筛.. 有负数的快读都打不对了..
来比较一下他们的区别?

inline int gn(int a=0,char c=0,int f=1){for(;(c<48||c>57)&&c!='-';c=getchar());if(c=='-')f=-1,c=getchar();for(;c>47&&c<58;c=getchar()) a=a*10+c-'0'; return a*f;
}
inline int gn(int a=0,char c=0,bool f=1){for(;(c<48||c>57)&&c!='-';c=getchar());if(c=='-')f=-1,c=getchar();for(;c>47&&c<58;c=getchar()) a=a*10+c-'0'; return a*f;
}
inline int gn(int a=0,char c=0,bool f=1){for(;(c<48||c>57)&&c!='-';c=getchar());if(c=='-')f=-1;for(;c>47&&c<58;c=getchar()) a=a*10+c-'0'; return a*f;
}

Emmmm 于是就愉快的残掉了..

好吧回到正题.
这个题网上的题解好少啊OvO
毕竟bzoj有10道sdoi2008, 这题就属于被忽略的题目之一...
不知道为什么…

数据范围p<=12p一眼状压…
我们可以用12位二进制表示一个集合…
这样定义状态fx,sf_{x,s}为第ii个节点上安排集合ss的状态…
这样的话ss就是每个儿子和安排在该点的集合们的并集…
但是很多个儿子差集就不好取了, 考虑多叉树转二叉树…
然而似乎传统的左儿子右兄弟是不行的… 我们考虑另一种转化方式..

比如我们有一棵这样的树:

转成一棵抉择方案等价的树是这样的:

这里我们对于有多个子树的节点, 建立虚拟节点(注意:虚拟节点是不能安排集合的)
如果有好多子树就继续递归下去(比如如果1有2 3 4 5四个子树, 那么就在10的右儿子挂一个12, 然后把4 5分别放在12的左右儿子.
由于有些点不能放集合, 我们定义gx,sg_{x,s}表示在以xx为根的子树中不在xx节点安排集合时的最大价值.
这样我们就可以根据二叉树写出状态转移方程:

fx,s=⎧⎩⎨⎪⎪max{gx,k−costs−k}+vals(k⊆s),x<=ngx,s,x>ngx,s=max{fl,k+fr,s−k}(k⊆s)

f_{x,s}=\left\{\begin{matrix} max\{g_{x,k}-cost_{s-k}\}+val_s (k\subseteq s),\; xn \end{matrix}\right.\\ g_{x,s}=max\{f_{l,k}+f_{r,s-k}\}(k\subseteq s)
根据这个状态转移方程推就行了…
不过好像是有些卡时间的…
我们可以预处理出某个集合的费用 costcost和价值 valval
然后枚举子集是有技巧的:

for(int k=s;k;k=(k-1)&s){}

这样会快一点… 大约能把复杂度从4n4^n降到3n3^n左右…
不过要记得特殊处理空集(因为这样枚举的k<script type="math/tex" id="MathJax-Element-14">k</script>不会到0)
就做完了…

代码(压常数版):
由于压了常数变得非常丑(本来写的也没多好看OvO)…

#include <cstdio>
#include <cstdio>
#include <cstring>
#define ri register int
const int N=204,P=4100,I=-1061109568;
int f[N][P],g[N][P],du[N>>1];
int w[N][13],val[P],Val[P],cost[N][P];
int ch[2][N],n,nn,p,t; bool vis[N];
int a,b,s;
inline int gi(int a=0,char c=0){for(;c<48||c>57;c=getchar());for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
}
inline int gn(int a=0,char c=0,int f=1){for(;(c<48||c>57)&&c!='-';c=getchar());if(c=='-')f=-1,c=getchar();for(;c>47&&c<58;c=getchar()) a=a*10+c-'0'; return a*f;
}
inline int max(const int &a,const int &b){return a>b?a:b;}
inline int min(const int &a,const int &b){return a<b?a:b;}
struct edge{int to,next;
}e[N]; int v[N>>1],tot;
inline void buildedge(const int &x,const int &y){e[++tot].to=y; e[tot].next=v[x]; v[x]=tot; ++du[x];e[++tot].to=x; e[tot].next=v[y]; v[y]=tot; ++du[y];
}
void dfs1(int x){int now=x; vis[x]=1;for(ri i=v[x];i;i=e[i].next){int y=e[i].to;if(!vis[y]){if(!ch[0][now]) ch[0][now]=y;       else if(du[x]==1) ch[1][now]=y;else ch[1][now]=++nn,now=nn,ch[0][now]=y;--du[y];--du[x]; dfs1(y);}}
}
int G(int x,int zt);
int F(int x,int zt){if(f[x][zt]>I) return f[x][zt];if(x>n) return G(x,zt);f[x][zt]=Val[zt]-cost[x][zt];for(ri z=zt;z;z=(z-1)&zt)f[x][zt]=max(f[x][zt],G(x,z)-cost[x][zt^z]+Val[zt]);return f[x][zt];
}
int G(int x,int zt){if(!ch[0][x]&&!ch[1][x]) return I;if(g[x][zt]>I) return g[x][zt];if(!ch[1][x])g[x][zt]=F(ch[0][x],zt);else if(!ch[0][x])g[x][zt]=F(ch[1][x],zt);else{for(ri z=zt;z;z=(z-1)&zt)g[x][zt]=max(g[x][zt],F(ch[0][x],z)+F(ch[1][x],zt^z));g[x][zt]=max(g[x][zt],F(ch[1][x],0)+F(ch[1][x],zt));}return g[x][zt];
}
int main(){nn=n=gi(); p=gi();memset(f,192,sizeof(f));memset(g,192,sizeof(g));for(ri i=1;i<n;++i){a=gi(),b=gi();buildedge(a,b);}for(ri i=1;i<=n;++i)for(ri j=1;j<=p;++j)w[i][j]=gi();t=gn();for(ri i=1;i<=t;++i){a=gn(),b=gi(),s=0;for(ri j=0;j<b;++j)s|=(1<<(gn()-1));val[s]+=a;} dfs1(1);for(ri i=0;i<1<<p;++i){for(ri j=i;j;j=(j-1)&i)Val[i]+=val[j];for(ri j=1;j<=n;++j)for(ri k=1;k<=p;++k)if(i&(1<<(k-1)))cost[j][i]+=w[j][k];}printf("%d\n",F(1,(1<<p)-1));
}

【学术篇】SDOI2008 山贼集团相关推荐

  1. P2465 [SDOI2008]山贼集团 dp

    这个题是一道树形dp+状压dp二合一,先预处理每种组合会有什么额外的费用,然后在树上dp就行了. 题干: 题目描述某山贼集团在绿荫村拥有强大的势力,整个绿荫村由N个连通的小村落组成,并且保证对于每两个 ...

  2. [SDOI2008]山贼集团【树上背包+状压】

    洛谷P2465 SOL 比较经典的一类树上背包问题套一个子集状压枚举. 注意到代价的计算与所选的点的集合有关,如果我们要统计代价需要状压记录点集,而数据范围非常配合的给了P≤12P\le12P≤12, ...

  3. 洛咕 P2465 [SDOI2008]山贼集团

    裸的状压dp. 设f[i][j]表示在i字数内放j集合的分部,直接sb转移. // luogu-judger-enable-o2 #include<bits/stdc++.h> #defi ...

  4. 【[SDOI2008]山贼集团】

    非常好的一道题 树上的状压\(dp\) 根据数据范围我们就能知道这是一道需要状压的题目 所以状态就是\(dp[i][S]\)表示在以\(i\)为根的子树里,选择的状态为\(S\)的最大收益 这个收益只 ...

  5. 【SDOI2008】山贼集团

    本题的模型是树形状态压缩的动态规划. 首先考虑简单的题目模型:对于任何形态的有根树 T,都可以建立其等效二叉树 T',若在原树 T 中,结点 x 有儿子c1,c2,c3,-,ck c1,c2,c3,- ...

  6. [FROM WOJ]#2040 山贼集团

    #2040 山贼集团 SDOI2008 题面 某山贼集团在绿荫村拥有强大的势力,整个绿荫村由N个连通的小村落组成,并且保证对于每两个小村落有且仅有一条简单路径相连.小村落用阿拉伯数字编号为1,2,3, ...

  7. 2018人工智能期末考试复习资料(一):学术篇

    机器之心知识委员会 机心通知函[2018]002号 2018 年人工智能专业期末考试复习资料:学术篇 各人工智能研究者.工程师.从业人: 2018 年是人工智能迅猛发展的一年,从技术研究到产业应用都取 ...

  8. 山贼集团 (group)

    山贼集团 (group) 题目描述 某山贼集团在绿荫村拥有强大的势力,整个绿荫村由N个连通的小村落组成,并且保证对于每两个小村落有且仅有一条简单路径相连.小村落用阿拉伯数字编号为1,2,3,4,-,n ...

  9. 我的八年博士生涯(学术篇)

    点击上方"码农突围",马上关注 这里是码农充电第一站,回复"666",获取一份专属大礼包 真爱,请设置"星标"或点个"在看&quo ...

最新文章

  1. 赠书 | 一文了解预训练语言模型
  2. 记录某项目中的踩坑与解决(持续更新)
  3. golang 实现 while 和 do……while 循环
  4. Apache OpenWebBeans 发布适用于 Java EE 微服务的 Meecrowave 服务器 1.0
  5. 英国出土1600年前的文物,上面居然刻着简体中文?!
  6. 机器学习知识总结系列-机器学习中的数学-概率与数理统计(1-3-1)
  7. 3005-基于二叉链表的二叉树最大宽度的计算(附思路,注释,可能错误分析)
  8. windows10下安装JDK及环境变量设置
  9. 985计算机只考数据结构,初试只考数据结构的985院校
  10. linux 命令之df持续更新中~
  11. 计算机组成原理在线实验,《计算机组成原理》实验.doc
  12. wince6.0添加组件_WINCE6.0添加对viewrs(PDF,Word,Execel和PowerPoint)支持
  13. 监听下拉框,当前选中值
  14. CRUD搬砖两三年了,怎么阅读Spring源码?
  15. 《C语言入门经典》读后感(一)
  16. HenCoder UI 部分 2-1 布局基础
  17. 机器学习必看的28个视频
  18. 杭州优科豪马轮胎有限公司北京经销商
  19. 能自行调节温度的新型织物 马里兰大学新发明引发讨论
  20. 教你认识正斜杠(/)与反斜杠(\)

热门文章

  1. 求水平渐近线和铅直渐近线
  2. Python相关的文件扩展名
  3. 再谈 RocketMQ broker busy(实战篇)
  4. 2D转换transform--rotate旋转(日志)
  5. 最新美团代付源码+支持多模板/多支付通道/全开源
  6. Mel,Bark以及ERB刻度
  7. ORA-22922: 不存在的 LOB 值 处理方法
  8. 今宵除夕夜,天涯共此时
  9. matlab在管理学中的应用简述【一】
  10. 那些年啊 那些事 一个程序员的奋斗史 98