Helga Hufflepuff's Cup CodeForces - 855C

题意:给一棵n个节点的树,要给每一个节点一个附加值,附加值可以为1-m中的一个整数。要求只能有最多x个节点有附加值k。如果某个节点的附加值是k,那么与其直接相连的点的附加值都必须小于k。求给整棵树的点赋附加值时满足要求的总方案数。

方法:

http://blog.csdn.net/ssimple_y/article/details/78081586

ans[i][j][k]表示以i节点为根的子树上选j个最高值且k满足条件(k=0表示i选比k小的值,k=1表示i选值为k,k=2表示i选比k大的值)时有多少种方法。显然,可以以任何一个节点为根开始dp。

对于每一个节点,计算其结果的方法要用一个小的dp。

t[i][j][p]表示(当前节点的)前i个子结点在情况p下选j个(p为0或1或2)的方案数。设第i子结点为xx。

在开始之前,由于即使一个子节点也不考虑,k=0,1,2时分别也有k-1,1,m-k种方法,也就是子节点的方案数还都要再分别乘以k-1,1,m-k,要先赋到t数组中。

$t[i][j][0]=sum\{t[i-1][j-y][0]*(ans[xx][y][0]+ans[xx][y][1]+ans[xx][y][2])\}$

$t[i][j][1]=sum\{t[i-1][j-y][1]*(ans[xx][y][0])\}$

$t[i][j][2]=sum\{t[i-1][j-y][2]*(ans[xx][y][0]+ans[xx][y][2])\}$

最后对于每个节点u,其ans[u][j][k]就等于t[u的子节点数量][j][k]。

当然,可以使用滚动数组优化t。

 #include<cstdio>
#include<cstring>
#define md 1000000007
typedef long long LL;
struct Edge
{
LL to,next;
}edge[];
LL k,m,n,x,anss;
LL f1[],n_e;
LL ans[][][];
bool vis[];
void m_e(LL a,LL b)
{
edge[++n_e].to=b;
edge[n_e].next=f1[a];
f1[a]=n_e;
edge[++n_e].to=a;
edge[n_e].next=f1[b];
f1[b]=n_e;
}
void dfs(LL u)
{
vis[u]=true;
LL kk,xx,j,q,ii=;
LL t[][][];//滚动数组
memset(t[],,sizeof(t[]));
t[][][]=k-;
t[][][]=;
t[][][]=m-k;
for(kk=f1[u];kk!=;kk=edge[kk].next)
{
if(!vis[edge[kk].to])
{
ii^=;
memset(t[ii],,sizeof(t[ii]));
xx=edge[kk].to;
dfs(xx);
memset(t[ii],,sizeof(t[ii]));
for(j=;j<=x;j++)
for(q=;q<=x;q++)
{
if(j<q) break;
t[ii][j][]=(t[ii][j][]+t[ii^][j-q][]*(ans[xx][q][]+ans[xx][q][]+ans[xx][q][]))%md;
t[ii][j][]=(t[ii][j][]+t[ii^][j-q][]*ans[xx][q][])%md;
t[ii][j][]=(t[ii][j][]+t[ii^][j-q][]*(ans[xx][q][]+ans[xx][q][]))%md;
}
}
}
memcpy(ans[u],t[ii],sizeof(ans[u]));
}
int main()
{
LL a,b,i,j;
scanf("%I64d%I64d",&n,&m);
for(i=;i<n;i++)
{
scanf("%I64d%I64d",&a,&b);
m_e(a,b);
}
scanf("%I64d%I64d",&k,&x);
dfs();
for(i=;i<=x;i++)
for(j=;j<;j++)
anss=(anss+ans[][i][j])%md;
printf("%I64d",anss);
return ;
}

实际实现中,可以每计算完一个子节点的所有t值,就将其赋到ans[u]上,在计算下一个节点时,例如要访问t[i-1][j-y][2],就相当于这种方法的ans[u][j-y][2]。这样可以避免每个子节点都要多开一个t数组。

 #include<cstdio>
#include<cstring>
#define md 1000000007
typedef long long LL;
struct Edge
{
LL to,next;
}edge[];
LL k,m,n,x,anss;
LL f1[],n_e;
LL ans[][][];
LL t[][];
bool vis[];
void m_e(LL a,LL b)
{
edge[++n_e].to=b;
edge[n_e].next=f1[a];
f1[a]=n_e;
edge[++n_e].to=a;
edge[n_e].next=f1[b];
f1[b]=n_e;
}
void dfs(LL u)
{
vis[u]=true;
LL kk,xx,j,q;
ans[u][][]=k-;
ans[u][][]=;
ans[u][][]=m-k;
for(kk=f1[u];kk!=;kk=edge[kk].next)
{
if(!vis[edge[kk].to])
{
xx=edge[kk].to;
dfs(xx);
memset(t,,sizeof(t));
for(j=;j<=x;j++)
for(q=;q<=x;q++)
{
if(j<q) break;
t[j][]=(t[j][]+ans[u][j-q][]*(ans[xx][q][]+ans[xx][q][]+ans[xx][q][]))%md;
t[j][]=(t[j][]+ans[u][j-q][]*ans[xx][q][])%md;
t[j][]=(t[j][]+ans[u][j-q][]*(ans[xx][q][]+ans[xx][q][]))%md;
}
for(j=;j<=x;j++)
for(q=;q<;q++)
ans[u][j][q]=t[j][q];
}
}
}
int main()
{
LL a,b,i,j;
scanf("%I64d%I64d",&n,&m);
for(i=;i<n;i++)
{
scanf("%I64d%I64d",&a,&b);
m_e(a,b);
}
scanf("%I64d%I64d",&k,&x);
dfs();
for(i=;i<=x;i++)
for(j=;j<;j++)
anss=(anss+ans[][i][j])%md;
printf("%I64d",anss);
return ;
}

错误记录:

(第二份代码)

曾经忘了写40行,导致数组越界访问WA。

曾经按照第一份代码的做,却没有每一次dfs单独开一个t数组,导致WA。

官方题解:

http://codeforces.com/blog/entry/54750

http://codeforces.com/blog/entry/54750?#comment-387718

This problem can be solved using precomputation of dp table dp[base][mask][len]. This stores the number of integers in base b and length len that forms the given mask in their representation. The mask is defined as having i - th bit as 1, if the digit i - 1 occurs odd number of times in the representation.

Using this precomputed dp array, we can easily calculate the answer for the queries, by converting l - 1 and r to the given base b, then adding the total integers less than equal to r with mask = 0 and subtracting those less than l with mask = 0.

Now, to find the number of integers less than equal to l - 1 with mask = 0, we first add all the integers with mask = 0 who have length less than length of l - 1 in base b representation. If length of l - 1 in base b is lb, this value can be calculated as . The second term is subtracted to take into account the trailing zeros.

Now, we need to calculate the number of integers with length = lb and value ≤ l - 1 and mask = 0. Let the number l - 1 in base brepresentation be l0, l1... llb. Then, if we fix the first digit of our answer, x from 0 to l0 - 1, we can simply calculate the mask for remaining digits we need as 2x and thus adding dp[b][2x][len - 1] to answer.

Now, if we fix the first digit as l0 only, we can simply perform the same operation for the second digit, selecting value of second digit, yfrom 0 to l1 - 1, and thus adding  to answer. And, we can move forward to rest of the digits in the same way.

The overall complexity of the solution will be 

let's say we want to calculate dp[v][j][x] (means the number of ways of getting x number of k type nodes in the subtree rooted at v, where type(v)=j) how to calculate this — let's assume f(v, j, x) has the same definition as dp[v][j][x].

say we have n children of node v. so essentially what we need to find is the number of ways to distribute x among these n children.

here we can use a dp. (for convenience I'll call nodes of type k as special node) Now, to do this computation at node v, we will form another DP dp1. We say  as the number of ways to choose a total of x special nodes from subtrees defined by v1,  v2,  ...,  vi i.e. from first i nodes. The recurrence can be defined as  , i.e. we are iterating over y assuming that subtree of vi contributes y special nodes and rest x-y special nodes have been contributed by previous i-1 nodes. So, finally dp[v][j][x] = dp1(n, j, x)

In the editorial solution this dp1 is denoted by a and b array. you wont find i in the editorial's dp1 state, i can be avoided by using two arrays a and b. we store dp1(i, , ) in b array, and after its calculation it is added to a array, so this will become dp1(i - 1, , ) for the next iteration.

Helga Hufflepuff's Cup CodeForces - 855C的更多相关文章

  1. Codeforces 855C - Helga Hufflepuff's Cup

    855C - Helga Hufflepuff's Cup 题意 要求构建一棵树,树上至多可以存在 \(x\) 个权值为 \(k\) 的重要点,且与重要点连边的点的权值必须小于 \(k\),问有多少种 ...

  2. C. Helga Hufflepuff's Cup 树形dp 难

    C. Helga Hufflepuff's Cup 这个题目我感觉挺难的,想了好久也写了很久,还是没有写出来. dp[i][j][k] 代表以 i 为根的子树中共选择了 j 个特殊颜色,且当前节点 i ...

  3. codeforces:Helga Hufflepuff's Cup

    题目大意:有一个包含n个顶点的无向无环连通图G,图中每个顶点都允许有一个值type,type的范围是1~m.有一个特殊值k,若一个顶点被赋值为k,则所有与之相邻的顶点只能被赋小于k的值.最多有x个顶点 ...

  4. 855C Helga Hufflepuff's Cup

    传送门 题目大意 给你一棵树,可以染m种颜色,现定义一种特殊的颜色K,一棵树上最多能有x个特殊颜色.如果一个节点为特殊颜色,那么他相邻的节点的值只能选比K小的颜色,问一共有多少种染色方案. 分析 不难 ...

  5. 【codeforces Manthan, Codefest 17 C】Helga Hufflepuff's Cup

    [链接]h在这里写链接 [题意]     k是最高级别的分数,最高界别的分数最多只能有x个.     1<=k<=m;     和k相邻的点的分数只能小于k;     n个点的树,问你每个 ...

  6. 【DP】【CF855C】 Helga Hufflepuff's Cup

    Description 给你一个树,可以染 \(m\) 个颜色,定义一个特殊颜色 \(k\) , 要求保证整棵树上特殊颜色的个数不超过 \(x\) 个.同时,如果一个节点是特殊颜色,那么它的相邻节点的 ...

  7. Codeforces 855C. Helga Hufflepuff's Cup----树形DP

    z最近在学习树形DP...好难啊. 在cf上找到了一题c题当模版马克一下. 题目不贴了..>>http://codeforces.com/problemset/problem/855/C& ...

  8. Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2)(A.暴力,B.优先队列,C.dp乱搞)

    A. Carrot Cakes time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  9. C.Fountains(Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2)+线段树+RMQ)

    题目链接:http://codeforces.com/contest/799/problem/C 题目: 题意: 给你n种喷泉的价格和漂亮值,这n种喷泉题目指定用钻石或现金支付(分别用D和C表示),C ...

随机推荐

  1. hdoj 4932 Miaomiao&#39;s Geometry 【暴力枚举】

    题意:在一条直线上有n个点.取一长度差为x的区间. 规定点必须是区间的端点. 让你找出来最大的x 策略:rt 分析可得:两个相邻点之间的区间要么是两个点的差,要么就是两个点的差的一半,那我们就简单枚举 ...

  2. 设计模式学习笔记——Mediator中介者模式

    将众多对象之间的网状关系转为全部通过一个中间对象间接发生关系,此中间对象为中介者. 看图最直观: 作用不言而喻,就是降低对象之间的耦合度,乃至降低了整个系统的复杂度. 有点象代理模式,更象外观模式:

  3. jvm 调优(2)垃圾回收算法

    可以从不同的的角度去划分垃圾回收算法: 按照基本回收策略分 引用计数(Reference Counting): 比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数. ...

  4. Serialization and deserialization are bottlenecks in parallel and distributed computing, especially in machine learning applications with large objects and large quantities of data.

    Serialization and deserialization are bottlenecks in parallel and distributed computing, especially ...

  5. DOM操作三

    1.以一个对象的x和y属性的方式返回滚动条的偏移量 function getScrollOffsets(w){ //使用指定的窗口,如果不带参数则使用当前窗口 w= w || window; //除了 ...

  6. Ruby map、each、select、inject、collect 、detect reference

    参考 https://ruby-china.org/topics/26718 map:(collect是map的别名函数) 对数组中每个元素进行表达式操作,原始数组不会被改变,返回执行表达式结果的新数 ...

  7. 详解likely和unlikely函数【转】

    本文转载自:http://blog.csdn.net/npy_lp/article/details/7175517 内核源码:Linux-2.6.38.8.tar.bz2 参考文档:http://gc ...

  8. Ural 1109 Conference(最小路径覆盖数)

    题意:A国家有M个代表,B国有N个代表,其中有K对代表可以进行谈判(一个是A国的,一个是B国的),并且每一个代表至少被包含在其中一对中(也就是说,每个人可以至少找到另外一个人谈判),每一对谈判需要一对 ...

  9. Android 增,删,改,查 通讯录中的联系人

    一.权限 操作通讯录必须在AndroidManifest.xml中先添加2个权限, <uses-permission android:name="android.permission. ...

  10. 黑马传智JavaEE57期 2019最新基础+就业+在职加薪_汇总

    黑马传智JavaEE57期 2019最新基础+就业+在职加薪 阶段1 语言基础+高级· 1-1-Java基础语法 第14节 数组 111