codeforces:Helga Hufflepuff's Cup

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



  这是一道树形DP的题目。由于是无环无向连通图,因此可以任选一个顶点R作为根结点,从而构造一颗树TREE。为每个顶点N维护一个属性maybe[3][x+1]。其中maybe[0][i]表示当N被赋小于k的值时,N及其所有后代结点总共出现i个被赋值为k的结点的总共组合数。而maybe[1][i]表示当N被赋值为k时,N及其所有后代结点总共出现i个被赋值为k的结点的总共组合数。maybe[2][i]表示当N被赋值大于k时,N及其所有后代结点总共出现i个被赋值为k的结点的总共组合数。

  若A、B、C三个结点是独立的,且A有a种状态,B有b种状态,C有c种状态,那么仅考虑A、B、C的情况下最多有abc种状态。因此可以看出状态数的计算应该是结合的。同样若A有a1种状态1和a2种状态2,且B有b1种状态3和b2种状态4,且当A为状态1与B为状态3是互斥的,而A为状态2与B为状态4是互斥的,那么仅考虑A与B最多有a1b2+a2b1种状态。

  计算某个结点N的maybe数组的流程可以总结如下:先创建一个与maybe等大的数组statePre和statePost。statePre用于记录前置状态,而statePost用于记录后置状态。一开始先将statePre初始化为仅一个N结点时的可能状态数目。之后遍历所有子结点,对于每一个子结点S进行下述操作:

  statePost[0][i] = statePre[0][0] * (S.maybe[0][i] + S.maybe[1][i] + S.maybe[2][i]) + ... + statePre[0][i] * (S.maybe[0][0] + S.maybe[1][0] + S.maybe[2][0])

  statePost[1][i] = statePre[1][0] * S.maybe[0][i] + ... statePre[1][i] * S.maybe[0][0]

  statePost[2][i] = statePre[2][0] * (S.maybe[0][i] + S.maybe[2][i]) + ... + statePre[2][i] * (S.maybe[0][0] + S.maybe[2][0])

  之后用用statePost的值覆盖statePre,并清空statePost。直到所有子结点全部遍历完毕,maybe即为statePre。

  而最终结果是累加R[0][0], ... , R[0][x], R[1][0], ... , R[1][x], R[2][0], ... ,R[2][x]得到的加总,即各种情况下组合数的总和。

  每个顶点有且仅有一个父顶点,而顶点的maybe数组在参与到父亲的maybe数组的计算过程总共时间费用为O(3*x^2)。而顶点总数是n,因此总的时间复杂度为O(3*n*x^2)。  



  下面给出JAVA代码:

  1 package cn.dalt.codeforces;
  2
  3 import java.io.BufferedInputStream;
  4 import java.io.IOException;
  5 import java.io.InputStream;
  6 import java.io.PushbackInputStream;
  7 import java.math.BigDecimal;
  8 import java.util.ArrayList;
  9 import java.util.List;
 10
 11 /**
 12  * Created by Administrator on 2017/9/24.
 13  */
 14 public class HelgaHufflepuffsCup {
 15
 16     final int LESS_THAN_K = 0;
 17     final int EQUAL_TO_K = 1;
 18     final int GREATER_THAN_K = 2;
 19     int n;
 20     int m;
 21     int k;
 22     int x;
 23     Node[] allNodes;
 24     long[][] backup;
 25     long modulo = 1000000000 + 7;
 26     int lessInitVal;
 27     int equalInitVal;
 28     int greaterInitVal;
 29
 30     public static void main(String[] args) throws Exception {
 31         HelgaHufflepuffsCup solution = new HelgaHufflepuffsCup();
 32         solution.init();
 33         long result = solution.solve();
 34         System.out.println(result);
 35     }
 36
 37     public void init() throws Exception {
 38         AcmInputReader input = new AcmInputReader(System.in);
 39         n = input.nextInteger();
 40         m = input.nextInteger();
 41
 42         allNodes = new Node[n];
 43         for (int i = 0; i < n; i++) {
 44             allNodes[i] = new Node();
 45             allNodes[i].id = i + 1;
 46         }
 47         for (int i = 1; i < n; i++) {
 48             int n1 = input.nextInteger() - 1;
 49             int n2 = input.nextInteger() - 1;
 50             allNodes[n1].nearBy.add(allNodes[n2]);
 51             allNodes[n2].nearBy.add(allNodes[n1]);
 52         }
 53
 54         k = input.nextInteger();
 55         x = input.nextInteger();
 56     }
 57
 58     public long solve() {
 59         //Mark allNodes[0] as the root of tree
 60         backup = new long[3][x + 1];
 61
 62         lessInitVal = k - 1;
 63         equalInitVal = 1;
 64         greaterInitVal = m - k;
 65
 66         detect(allNodes[0], null);
 67
 68         long sum = 0;
 69         for (int i = 0; i < 3; i++) {
 70             for (int j = 0; j <= x; j++) {
 71                 sum += allNodes[0].maybe[i][j];
 72             }
 73         }
 74         return sum % modulo;
 75     }
 76
 77     public void detect(Node node, Node parent) {
 78         long[][] maybe = new long[3][x + 1];
 79
 80         maybe[0][0] = lessInitVal;
 81         maybe[1][1] = equalInitVal;
 82         maybe[2][0] = greaterInitVal;
 83
 84         for (Node nearby : node.nearBy) {
 85             if (nearby == parent) {
 86                 continue;
 87             }
 88
 89             detect(nearby, node);
 90             combineInto(backup, maybe, nearby.maybe);
 91             {
 92                 long[][] tmp = backup;
 93                 backup = maybe;
 94                 maybe = tmp;
 95             }
 96         }
 97
 98         node.maybe = maybe;
 99     }
100
101     public void combineInto(long[][] result, long[][] father, long[][] kid) {
102         for (int i = 0; i <= x; i++) {
103             long result0i = 0;
104             long result1i = 0;
105             long result2i = 0;
106             for (int j = 0; j <= i; j++) {
107                 result0i += (father[0][i - j] * (kid[0][j] + kid[1][j] + kid[2][j])) % modulo;
108                 result1i += (father[1][i - j] * kid[0][j]) % modulo;
109                 result2i += (father[2][i - j] * (kid[0][j] + kid[2][j])) % modulo;
110             }
111             result[0][i] = result0i % modulo;
112             result[1][i] = result1i % modulo;
113             result[2][i] = result2i % modulo;
114         }
115     }
116
117
118     static class Node {
119         List<Node> nearBy = new ArrayList<>();
120         long[][] maybe;
121         int id;
122
123         @Override
124         public String toString() {
125             StringBuilder sb = new StringBuilder();
126             sb.append(id);
127             sb.append("\n");
128             if (maybe != null) {
129                 for (int i = 0; i < 3; i++) {
130                     for (int j = 0; j < maybe[i].length; j++) {
131                         sb.append(maybe[i][j]);
132                         sb.append(", ");
133                     }
134                     sb.setLength(sb.length() - 2);
135                     sb.append("\n");
136                 }
137             }
138             return sb.toString();
139         }
140     }
141
142     /**
143      * @author dalt
144      * @see java.lang.AutoCloseable
145      * @since java1.7
146      */
147     static class AcmInputReader implements AutoCloseable {
148         private PushbackInputStream in;
149
150         /**
151          * 创建读取器
152          *
153          * @param input 输入流
154          */
155         public AcmInputReader(InputStream input) {
156             in = new PushbackInputStream(new BufferedInputStream(input));
157         }
158
159         @Override
160         public void close() throws IOException {
161             in.close();
162         }
163
164         private int nextByte() throws IOException {
165             return in.read() & 0xff;
166         }
167
168         /**
169          * 如果下一个字节为b,则跳过该字节
170          *
171          * @param b 被跳过的字节值
172          * @throws IOException if 输入流读取错误
173          */
174         public void skipByte(int b) throws IOException {
175             int c;
176             if ((c = nextByte()) != b) {
177                 in.unread(c);
178             }
179         }
180
181         /**
182          * 如果后续k个字节均为b,则跳过k个字节。这里{@literal k<times}
183          *
184          * @param b     被跳过的字节值
185          * @param times 跳过次数,-1表示无穷
186          * @throws IOException if 输入流读取错误
187          */
188         public void skipByte(int b, int times) throws IOException {
189             int c;
190             while ((c = nextByte()) == b && times > 0) {
191                 times--;
192             }
193             if (c != b) {
194                 in.unread(c);
195             }
196         }
197
198         /**
199          * 类似于{@link #skipByte(int, int)}, 但是会跳过中间出现的空白字符。
200          *
201          * @param b     被跳过的字节值
202          * @param times 跳过次数,-1表示无穷
203          * @throws IOException if 输入流读取错误
204          */
205         public void skipBlankAndByte(int b, int times) throws IOException {
206             int c;
207             skipBlank();
208             while ((c = nextByte()) == b && times > 0) {
209                 times--;
210                 skipBlank();
211             }
212             if (c != b) {
213                 in.unread(c);
214             }
215         }
216
217         /**
218          * 读取下一块不含空白字符的字符块
219          *
220          * @return 下一块不含空白字符的字符块
221          * @throws IOException if 输入流读取错误
222          */
223         public String nextBlock() throws IOException {
224             skipBlank();
225             StringBuilder sb = new StringBuilder();
226             int c = nextByte();
227             while (AsciiMarksLazyHolder.asciiMarks[c = nextByte()] != AsciiMarksLazyHolder.BLANK_MARK) {
228                 sb.append((char) c);
229             }
230             in.unread(c);
231             return sb.toString();
232         }
233
234         /**
235          * 跳过输入流中后续空白字符
236          *
237          * @throws IOException if 输入流读取错误
238          */
239         private void skipBlank() throws IOException {
240             int c;
241             while ((c = nextByte()) <= 32) ;
242             in.unread(c);
243         }
244
245         /**
246          * 读取下一个整数(可正可负),这里没有对溢出做判断
247          *
248          * @return 下一个整数值
249          * @throws IOException if 输入流读取错误
250          */
251         public int nextInteger() throws IOException {
252             skipBlank();
253             int value = 0;
254             boolean positive = true;
255             int c = nextByte();
256             if (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.SIGN_MARK) {
257                 positive = c == ‘+‘;
258             } else {
259                 value = ‘0‘ - c;
260             }
261             c = nextByte();
262             while (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.NUMERAL_MARK) {
263                 value = (value << 3) + (value << 1) + ‘0‘ - c;
264                 c = nextByte();
265             }
266
267             in.unread(c);
268             return positive ? -value : value;
269         }
270
271         /**
272          * 判断是否到了文件结尾
273          *
274          * @return true如果到了文件结尾,否则false
275          * @throws IOException if 输入流读取错误
276          */
277         public boolean isMeetEOF() throws IOException {
278             int c = nextByte();
279             if (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.EOF) {
280                 return true;
281             }
282             in.unread(c);
283             return false;
284         }
285
286         /**
287          * 判断是否在跳过空白字符后抵达文件结尾
288          *
289          * @return true如果到了文件结尾,否则false
290          * @throws IOException if 输入流读取错误
291          */
292         public boolean isMeetBlankAndEOF() throws IOException {
293             skipBlank();
294             int c = nextByte();
295             if (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.EOF) {
296                 return true;
297             }
298             in.unread(c);
299             return false;
300         }
301
302         /**
303          * 获取下一个用英文字母组成的单词
304          *
305          * @return 下一个用英文字母组成的单词
306          */
307         public String nextWord() throws IOException {
308             StringBuilder sb = new StringBuilder(16);
309             skipBlank();
310             int c;
311             while ((AsciiMarksLazyHolder.asciiMarks[(c = nextByte())] & AsciiMarksLazyHolder.LETTER_MARK) != 0) {
312                 sb.append((char) c);
313             }
314             in.unread(c);
315             return sb.toString();
316         }
317
318         /**
319          * 读取下一个长整数(可正可负),这里没有对溢出做判断
320          *
321          * @return 下一个长整数值
322          * @throws IOException if 输入流读取错误
323          */
324         public long nextLong() throws IOException {
325             skipBlank();
326             long value = 0;
327             boolean positive = true;
328             int c = nextByte();
329             if (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.SIGN_MARK) {
330                 positive = c == ‘+‘;
331             } else {
332                 value = ‘0‘ - c;
333             }
334             c = nextByte();
335             while (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.NUMERAL_MARK) {
336                 value = (value << 3) + (value << 1) + ‘0‘ - c;
337                 c = nextByte();
338             }
339             in.unread(c);
340             return positive ? -value : value;
341         }
342
343         /**
344          * 读取下一个浮点数(可正可负),浮点数是近似值
345          *
346          * @return 下一个浮点数值
347          * @throws IOException if 输入流读取错误
348          */
349         public float nextFloat() throws IOException {
350             return (float) nextDouble();
351         }
352
353         /**
354          * 读取下一个浮点数(可正可负),浮点数是近似值
355          *
356          * @return 下一个浮点数值
357          * @throws IOException if 输入流读取错误
358          */
359         public double nextDouble() throws IOException {
360             skipBlank();
361             double value = 0;
362             boolean positive = true;
363             int c = nextByte();
364             if (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.SIGN_MARK) {
365                 positive = c == ‘+‘;
366             } else {
367                 value = c - ‘0‘;
368             }
369             c = nextByte();
370             while (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.NUMERAL_MARK) {
371                 value = value * 10.0 + c - ‘0‘;
372                 c = nextByte();
373             }
374
375             if (c == ‘.‘) {
376                 double littlePart = 0;
377                 double base = 1;
378                 c = nextByte();
379                 while (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.NUMERAL_MARK) {
380                     littlePart = littlePart * 10.0 + c - ‘0‘;
381                     base *= 10.0;
382                     c = nextByte();
383                 }
384                 value += littlePart / base;
385             }
386             in.unread(c);
387             return positive ? value : -value;
388         }
389
390         /**
391          * 读取下一个高精度数值
392          *
393          * @return 下一个高精度数值
394          * @throws IOException if 输入流读取错误
395          */
396         public BigDecimal nextDecimal() throws IOException {
397             skipBlank();
398             StringBuilder sb = new StringBuilder();
399             sb.append((char) nextByte());
400             int c = nextByte();
401             while (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.NUMERAL_MARK) {
402                 sb.append((char) c);
403                 c = nextByte();
404             }
405             if (c == ‘.‘) {
406                 sb.append(‘.‘);
407                 c = nextByte();
408                 while (AsciiMarksLazyHolder.asciiMarks[c] == AsciiMarksLazyHolder.NUMERAL_MARK) {
409                     sb.append((char) c);
410                     c = nextByte();
411                 }
412             }
413             in.unread(c);
414             return new BigDecimal(sb.toString());
415         }
416
417         private static class AsciiMarksLazyHolder {
418             public static final byte BLANK_MARK = 1;
419             public static final byte SIGN_MARK = 1 << 1;
420             public static final byte NUMERAL_MARK = 1 << 2;
421             public static final byte UPPERCASE_LETTER_MARK = 1 << 3;
422             public static final byte LOWERCASE_LETTER_MARK = 1 << 4;
423             public static final byte LETTER_MARK = UPPERCASE_LETTER_MARK | LOWERCASE_LETTER_MARK;
424             public static final byte EOF = 1 << 5;
425             public static byte[] asciiMarks = new byte[256];
426
427             static {
428                 for (int i = 0; i <= 32; i++) {
429                     asciiMarks[i] = BLANK_MARK;
430                 }
431                 asciiMarks[‘+‘] = SIGN_MARK;
432                 asciiMarks[‘-‘] = SIGN_MARK;
433                 for (int i = ‘0‘; i <= ‘9‘; i++) {
434                     asciiMarks[i] = NUMERAL_MARK;
435                 }
436                 for (int i = ‘a‘; i <= ‘z‘; i++) {
437                     asciiMarks[i] = LOWERCASE_LETTER_MARK;
438                 }
439                 for (int i = ‘A‘; i <= ‘Z‘; i++) {
440                     asciiMarks[i] = UPPERCASE_LETTER_MARK;
441                 }
442                 asciiMarks[0xff] = EOF;
443             }
444         }
445     }
446 }

codeforces:Helga Hufflepuff's Cup

时间: 2024-08-02 22:52:21

codeforces:Helga Hufflepuff's Cup的相关文章

Helga Hufflepuff&#39;s Cup CodeForces - 855C

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满

855C Helga Hufflepuff&#39;s Cup

传送门 题目大意 给你一棵树,可以染m种颜色,现定义一种特殊的颜色K,一棵树上最多能有x个特殊颜色.如果一个节点为特殊颜色,那么他相邻的节点的值只能选比K小的颜色,问一共有多少种染色方案. 分析 不难想出这是一个树型dp,用dp[i][j][k]表示考虑第i个点所选的颜色的种类为j,共用了k个特殊颜色.j的状态分别是0代表[1,K-1],1代表[K+1,m],2代表K.然后我们考虑如何转移.首先我们不难想到对于每种状态它是由之前哪种状态转移来的(见代码),对于k的枚举我们可以依次考虑一个点的所有

C. Helga Hufflepuff&#39;s Cup 树形dp 难

C. Helga Hufflepuff's Cup 这个题目我感觉挺难的,想了好久也写了很久,还是没有写出来. dp[i][j][k] 代表以 i 为根的子树中共选择了 j 个特殊颜色,且当前节点 i 的状态为 k 的染色方案数. k=0 ,代表当前节点 i 的颜色值小于 K . k=1,代表当前节点 i 的颜色值等于 K . k=2,代表当前节点 i 的颜色值大于 K . 但是这个dfs过程的处理我觉得很复杂. 我们需要一个数组来进行临时的存储. tmp[i][k] 表示选了 i 个  状态为

Codeforces Round #351 (VK Cup 2016 Round 3, Div. 2 Edition) B

#include<stdio.h> #include<algorithm> #include<vector> #include<string.h> using namespace std; int main() { int n,m,i; while(scanf("%d%d",&n,&m)!=EOF) { vector<int> da,xi; int a,b; int maxa=1,minb=n; for(i=1

Codeforces Round #348 (VK Cup 2016 Round 2, Div. 1 Edition) C. Little Artem and Random Variable 数学

C. Little Artem and Random Variable Little Artyom decided to study probability theory. He found a book with a lot of nice exercises and now wants you to help him with one of them. Consider two dices. When thrown each dice shows some integer from 1 to

Codeforces Round #351 (VK Cup 2016 Round 3, Div. 2 Edition)

A. Bear and Game 题意:一个体育节目,它可能在某一分钟是很有趣的,其他时间都是很无聊的,如果持续十五分钟都很无聊的话那么Bear就会关掉电视,问什么时候会关掉电视. 题解:用第i个有趣的时间减去第i-1个有趣的时间,如果差值大于十五分钟那就输出第i个有趣的时间+15.注意第一个有趣的时间要为0,最后一个为90. 代码: 1 /*A*/ 2 #include<cstdio> 3 using namespace std; 4 5 const int maxn=95; 6 7 int

Codeforces Round #348(VK Cup 2016 - Round 2)

A - Little Artem and Presents (div2) 1 2 1 2这样加就可以了 #include <bits/stdc++.h> typedef long long ll; const int N = 1e5 + 5; int main() { int n; scanf ("%d", &n); int ans = n / 3 * 2; if (n % 3) { ans++; } printf ("%d\n", ans);

Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3) B. T-Shirt Hunt

B. T-Shirt Hunt time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard output Not so long ago the Codecraft-17 contest was held on Codeforces. The top 25 participants, and additionally random 25 participant

Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) A. Single Wildcard Pattern Matching B. Pair of Toys C. Bracket Subsequence D. Array Restoration-区间查询最值(RMQ(ST))

Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) A. Single Wildcard Pattern Matching 题意就是匹配字符的题目,打比赛的时候没有看到只有一个" * ",然后就写挫了,被hack了,被hack的点就是判一下只有一个" * ". 1 //A 2 #include<iostream> 3 #include<cstdio&g