今天一月一号..

突然想安利一波我的中二的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<=12\)一眼状压...

我们可以用12位二进制表示一个集合...

这样定义状态\(f_{x,s}\)为第\(i\)个节点上安排集合\(s\)的状态...

这样的话\(s\)就是每个儿子和安排在该点的集合们的并集...

但是很多个儿子差集就不好取了, 考虑多叉树转二叉树...

然而似乎传统的左儿子右兄弟是不行的... 我们考虑另一种转化方式..

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



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



这里我们对于有多个子树的节点, 建立虚拟节点(注意:虚拟节点是不能安排集合的)

如果有好多子树就继续递归下去(比如如果1有2 3 4 5四个子树, 那么就在10的右儿子挂一个12, 然后把4 5分别放在12的左右儿子.

由于有些点不能放集合, 我们定义\(g_{x,s}\)表示在以\(x\)为根的子树中不在\(x\)节点安排集合时的最大价值.

这样我们就可以根据二叉树写出状态转移方程:

\[f_{x,s}=\left\{\begin{matrix}
max\{g_{x,k}-cost_{s-k}\}+val_s (k\subseteq s),\; x<=n\\
\\
g_{x,s},\; x>n
\end{matrix}\right.\\
g_{x,s}=max\{f_{l,k}+f_{r,s-k}\}(k\subseteq s)
\]

根据这个状态转移方程推就行了...

不过好像是有些卡时间的...

我们可以预处理出某个集合的费用\(cost\)和价值\(val\)

然后枚举子集是有技巧的:

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

}

这样会快一点... 大约能把复杂度从\(4^n\)降到\(3^n\)左右...

不过要记得特殊处理空集(因为这样枚举的\(k\)不会到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]山贼集团

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

  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. 山贼集团 (group)

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

  6. 【学术篇】SDOI2008 仪仗队

    Part1:传送门&吐槽 水题... 然而由于线筛里面的\(j\)打成了\(i\)然后就不能1A了OvO Part2:题目分析 这个正方形是对称的... 而且很显然对角线上只有一个点会被看到. ...

  7. 【学术篇】SDOI2008 沙拉公主的困惑

    传送门! 题目在这里... 题目大意? 难道不是说的很清楚了么OvO 求n!中与m!互质的数的个数.. 题目分析. 显然的数论... 所以就是化式子呗.. 一个很显然的性质就是如果\(gcd(a,b) ...

  8. 【Luogu】P2465山贼集团(树形状压DP)

    题目链接 写了个70分暴力还挂了,第一遍提交只拿了十分……海星 首先建虚拟节点多叉树转成二叉,然后子集枚举DP 设g[x][i]是以x为根的子树内山贼集合i,x啥都不选也没贡献的时候的最大价值 f[x ...

  9. 【学术篇】51nod 1238 最小公倍数之和

    这是一道杜教筛的入(du)门(liu)题目... 题目大意 求 \[ \sum_{i=1}^n\sum_{j=1}^nlcm(i,j) \] 一看就是辣鸡反演一类的题目, 那就化式子呗.. \[ \s ...

随机推荐

  1. next()nextLine()以及nextInt()的区别及用法【转载】

    next().nextLine().nextInt()作为scanner内置的方法,常常让人傻傻分不清楚,今天在这里记下他们的区别以及以此区别为出发点的用法:他们的区别在于对于空格的处理方式不同,以及 ...

  2. Java文件教程

    File类的对象是文件或目录的路径名的抽象表示. 创建文件 我们可以从以下创建一个File对象 - 一个路径名 一个父路径名和子路径名 一个URI (统一资源标识符) 可以使用File类的以下构造函数 ...

  3. 【三】Jmeter接口自动化测试系列之Http接口自动化实战

    作者:大虫 本文介绍 Jmeter 工具的 http 接口 自动化测试 实战! 为了通用性,就拿知乎 网站作为实战例子吧! 必备技能:http接口基础知识.抓包,本文不做详细介绍,不会的可以先百度恶补 ...

  4. Centos下的 docker安装

    安装一些必要的系统工具:sudo yum install -y yum-utils device-mapper-persistent-data lvm2 添加软件源信息:sudo yum-config ...

  5. C语言之文件包含

    c = #include <stdio.h> #include "A.h" int main() { /******************************** ...

  6. DataTable转对象Model

    我们经常需要从数据库表中取数,取数是以取DataTable的方式,但是我么希望以对象为单位进行这种操作.即存在把取到的DataTable(数据表)转换为ModelList(对象集合)的需求. 原理稍微 ...

  7. MapReduce计算原理及步骤

    步骤:input从HDFS读取内容, split()切割分片内容,key/value, map()方法对输入的key/value进行计算处理,先写到内存,在内存中进行分区.排序,之后将Key/valu ...

  8. 【归档】Mysql大表归档

    作为一个企业或者DBA,我们通常会有这种想法,数据是一个公司的核心命脉,应该需要永久保存,很多时候DBA和开发沟通的时候,开发人员也会这么告诉我们,这份数据非常重要,数据需要永久保存.然而,如果将数据 ...

  9. 开放应用模型(OAM):全球首个云原生应用标准定义与架构模型

    Kubernetes 项目作为容器编排领域的事实标准, 成功推动了诸如阿里云 Kubernetes (ACK)等云原生服务的迅速增长.但同时我们也关注到,Kubernetes 的核心 API 资源比如 ...

  10. java之短路与&&和短路或||

    短路的意思就是惰性计算,符号右边的就不进行计算了. ||和&&就是这样,