NOIP模拟17.8.15

A 债务
文件名 输入文件 输出文件 时间限制 空间限制
debt.pas/c/cpp debt.in debt.out 1s 128MB
【题目描述】
小 G 有一群好朋友,他们经常互相借钱。假如说有三个好朋友 A,B,C。A
欠 B 20 元,B 欠 C 20 元,总债务规模为 20+20=40 元。小 G 是个追求简约的人,
他觉得这样的债务太繁杂了。他认为,上面的债务可以完全等价为 A 欠 C 20 元,
B 既不欠别人,别人也不欠他。这样总债务规模就压缩到了 20 元。
现在给定 n 个人和 m 条债务关系。小 G 想找到一种新的债务方案,使得每个
人欠钱的总数不变,或被欠钱的总数不变(但是对象可以发生变化),并且使得总
债务规模最小。
【输入格式】
输入文件第一行两个数字 n, m,含义如题目所述。
接下来 m 行,每行三个数字 ai, bi, ci,表示 ai 欠 bi 的钱数为 ci。
注意,数据中关于某两个人 A 和 B 的债务信息可能出现多次,将其累加即可。
如”A 欠 B 20 元”、”A 欠 B 30 元”、”B 欠 A 10 元”,其等价为”A 欠 B 40 元”。
【输出格式】
输出文件共一行,输出最小的总债务规模。
【样例输入 1】
5 3
1 2 10
2 3 1
2 4 1
2
【样例输出 1】
10
【样例输入 2】
4 3
1 2 1
2 3 1
3 1 1
【样例输出 2】
0
【数据范围】
对于 30% 的数据,1 ≤ n ≤ 10,1 ≤ m ≤ 10。
对于 60% 的数据,1 ≤ n ≤ 100, 1 ≤ m ≤ 104。
对于 80% 的数据,1 ≤ n ≤ 104,1 ≤ m ≤ 104。
对于 100% 的数据,1 ≤ n ≤ 106,1 ≤ m ≤ 106。
对于所有的数据,保证 1 ≤ ai, bi ≤ n, 0 < ci ≤ 100。

【题解】

水题,无fuck说

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cstdlib>
  5. #define jue(a) (((a) >= 0) ? (a) : (-a))
  6.  
  7. const int INF = 0x3f3f3f3f;
  8. const int MAXN = + ;
  9.  
  10. inline void read(int &x)
  11. {
  12. x = ;char ch = getchar(), c = ch;
  13. while(ch < '' || ch > '') c = ch, ch = getchar();
  14. while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
  15. if(c == '-')x = -x;
  16. }
  17.  
  18. int n,m;
  19. int qian[MAXN], ans;//qian[i]正数表示第i个人被欠多少钱,负数表示欠别人多少钱
  20.  
  21. int main()
  22. {
  23. scanf("%d %d", &n, &m);
  24. register int tmp1, tmp2, tmp3;
  25. for(register int i = ;i <= m;++ i)
  26. {
  27. read(tmp1), read(tmp2), read(tmp3);
  28. qian[tmp1] -=tmp3;
  29. qian[tmp2] += tmp3;
  30. }
  31. for(register int i = ;i <= n;++ i) ans += jue(qian[i]);
  32. printf("%d", (ans >> ));
  33. return ;
  34. }

T1

B 排列
文件名 输入文件 输出文件 时间限制 空间限制
perm.pas/c/cpp perm.in perm.out 1s 128MB
【题目描述】
小 G 喜欢玩排列。现在他手头有两个 n 的排列。n 的排列是由 0, 1, 2, ..., n − 1
这 n 的数字组成的。对于一个排列 p,Order(p) 表示 p 是字典序第 Order(p) 小的
排列(从 0 开始计数)。对于小于 n! 的非负数 x,P erm(x) 表示字典序第 x 小的
排列。
现在,小 G 想求一下他手头两个排列的和。两个排列 p 和 q 的和为 sum =
P erm((Order(p) + Order(q))%n!)。
【输入格式】
输入文件第一行一个数字 n,含义如题。
接下来两行,每行 n 个用空格隔开的数字,表示小 G 手头的两个排列。
【输出格式】
输出一行 n 个数字,用空格隔开,表示两个排列的和。
【样例输入 1】
2
0 1
1 0
【样例输出 1】
1 0
4
【样例输入 2】
3
1 2 0
2 1 0
【样例输出 2】
1 0 2
【数据范围】
1、2、3、4 测试点,1 ≤ n ≤ 10。
5、6、7 测试点,1 ≤ n ≤ 5000,保证第二个排列的 Order ≤ 105。
8、9、10 测试点,1 ≤ n ≤ 5000。

【题解】

康托展开:

一个序列的排名(从0开始计数) = Rank[n]*(n-1)!+Rank[n-1]*(n-2)!+….
其中Rank[n]表示n位置上的数字在未出现过的数字中的排行,并且从0开始计数。

我们先求出两个序列的康托展开式,相加

但是显然阶乘爆掉

于是我们只加rank数组

如果rank[i]这一位大于等于i,就按i进制进位

证明:

……rank[i] * (i - 1) ! + rank[i + 1] * i !……

若rank[i] > i

那么可分解为

rank[i]%i * (i - 1)! + rank[i]/i * i! + rank[i + 1]*i!

所以进位显然

mod n!的话,只需要忽略rank[i + 1]即可

推式子这一步,我开始想的是类似一遍找一遍插入排序,复杂度n^2

天宇哥哥的做法是  从n往前找,p从-1向上累计,遇到没有用过的p就标记为用过,同时rank[n]--

因为num[i + 1..n]求出后能得知num[i]能选哪一些数   也就是num[1...i]有哪一些数  从小到大枚举到对应排名即可

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cstdlib>
  5.  
  6. inline void read(int &x)
  7. {
  8. x = ;char ch = getchar(), c = ch;
  9. while(ch < '' || ch > '')c = ch, ch = getchar();
  10. while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
  11. if(c == '-')x = -x;
  12. }
  13.  
  14. const int INF = 0x3f3f3f3f;
  15. const int MAXN = + ;
  16.  
  17. int num1[MAXN], num2[MAXN];
  18. int rank1[MAXN], rank2[MAXN];
  19. int n, b[MAXN];
  20.  
  21. int main()
  22. {
  23. read(n);
  24. for(register int i = n;i >= ;-- i) read(num1[i]);
  25. for(register int i = n;i >= ;-- i) read(num2[i]);
  26. register int p;
  27. for(register int i = ;i <= n;++ i)
  28. {
  29. p = ;
  30. for(register int j = ;j < i;++ j)if(num1[j] < num1[i]) ++ p;
  31. rank1[i] += p;
  32. p = ;
  33. for(register int j = ;j < i;++ j)if(num2[j] < num2[i]) ++ p;
  34. rank2[i] += p;
  35. rank1[i] += rank2[i];
  36. rank1[i + ] += rank1[i]/i;
  37. rank1[i] %= i;
  38. }
  39. rank1[n] %= n;
  40. for(register int i = n;i >= ;-- i)
  41. {
  42. p = -;
  43. while(rank1[i] >= )
  44. {
  45. ++ p;
  46. if(!b[p])-- rank1[i];
  47. }
  48. b[p] = ;
  49. printf("%d ", p);
  50. }
  51. return ;
  52. }

T2

C 剪树枝
文件名 输入文件 输出文件 时间限制 空间限制
tree.pas/c/cpp tree.in tree.out 1s 128MB
【题目描述】
rzyz 有一棵苹果树。苹果树有 n 个节点(也就是苹果),n − 1 条边(也就是
树枝)。调皮的小 G 爬到苹果树上。他发现这棵苹果树上的苹果有两种:一种是黑
苹果,一种是红苹果。小 G 想要剪掉 k 条树枝,将整棵树分成 k + 1 个部分。他
想要保证每个部分里面有且仅有一个黑苹果。请问他一共有多少种剪树枝的方案?
【输入格式】
第一行一个数字 n,表示苹果树的节点(苹果)个数。
第二行一共 n − 1 个数字 p0, p1, p2, p3, ..., pn−2,pi 表示第 i + 1 个节点和 pi 节
点之间有一条边。注意,点的编号是 0 到 n − 1。
第三行一共 n 个数字 x0, x1, x2, x3, ..., xn−1。如果 xi 是 1,表示 i 号节点是黑
苹果;如果 xi 是 0,表示 i 号节点是红苹果。
【输出格式】
输出一个数字,表示总方案数。答案对 109 + 7 取模。
【样例输入 1】
3
0 0
0 1 1
【样例输出 1】
2
【样例输入 2】
6
0 1 1 0 4
1 1 0 0 1 0
【样例输出 2】
1
【样例输入 3】
10
0 1 2 1 4 4 4 0 8
0 0 0 1 0 1 1 0 0 1
【样例输出 3】
27
【数据范围】
对于 30% 的数据,1 ≤ n ≤ 10。
对于 60% 的数据,1 ≤ n ≤ 100。
对于 80% 的数据,1 ≤ n ≤ 1000。
对于 100% 的数据,1 ≤ n ≤ 105。
对于所有数据点,都有 0 ≤ pi ≤ n − 1,xi = 0 或 xi = 1。
特别地,60% 中、80% 中、100% 中各有一个点,树的形态是一条链。

【题解】

做过的第二道树形DP,第一道A了的树形DP。我对树形DP理解还不够深入,所以下面的题解大家自行斟酌,

抱着江信江疑的态度看

正确性请尤其注意需要剪掉的时候,和每一个dp[i][1],能否保证性质:每个连通块有且仅有一个黑点

dp[i][0]表示 i节点不能提供给父亲黑节点的方案数

dp[i][1]表示i节点 能提供给父亲黑节点的而方案书

初始:所有叶节点e,若为黑:dp[e][1] = 1,dp[e][0] = 1(可以切断与父节点连边);若为白:dp[e][1] = 0, dp[e][0] = 1

转移:

若i为黑色节点:

dp[i][1] = πdp[son(i)][0]  这个地方保证了每个连通分块最多有一个黑节点

dp[i][0] = dp[i][1] 即i为黑节点不给父亲黑节点的方案只能是减掉,相当于dp[i][1],保证每个连通分块至少有一个黑节点

上述两条性质,使dp[i][1]的方案保证有且仅有一个黑节点

若i为白色节点:

dp[i][1] = Σ(dp[j][1] * πdp[son(i)][0])  son(i)不含j,j也是i的一个儿子  这个就是一个选黑,另一些选白    保证dp[i][1]的方案有且仅有一个黑节点

dp[i][0] = πdp[son(i)][0] + dp[i][1]  即下面全是白,和能提供黑但减掉与父亲节点的边

答案即为dp[i][1]

正确性我看了很久。。不知道对不对。。还请各位神犇指正

转移有奇淫技巧,见代码及注释

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cstdlib>
  5. #define max(a, b) ((a) > (b) ? (a) : (b))
  6.  
  7. inline void read(int &x)
  8. {
  9. x = ;char ch = getchar();char c = ch;
  10. while(ch < '' || ch > '')c = ch, ch = getchar();
  11. while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
  12. if(c == '-')x = -x;
  13. }
  14.  
  15. const int INF = 0X3f3f3f3f;
  16. const int MAXN = + ;
  17. const int MOD = + ;
  18.  
  19. struct Edge
  20. {
  21. int u,v,next;
  22. Edge(int _u, int _v, int _next){u = _u;v = _v;next = _next;}
  23. Edge(){}
  24. }edge[MAXN << ];
  25.  
  26. int head[MAXN], cnt;
  27.  
  28. inline void insert(int a, int b)
  29. {
  30. edge[++cnt] = Edge(a,b,head[a]);
  31. head[a] = cnt;
  32. }
  33.  
  34. int n,color[MAXN],dp[][MAXN],b[MAXN],fa[MAXN];
  35.  
  36. /*
  37. 若i为黑:
  38. dp[i][0] = dp[i][1]
  39. dp[i][1] = πdp[son][0]

  40. dp[i][0] = πdp[son][0]
  41. dp[i][1] = dp[i][1]
  42. 若i为白:
  43. dp[i][0] = πdp[son][0] + dp[i][1]
  44. dp[i][1] = Σdp[son1][1]* πdp[son(不含son1)][0]
  45.  
  46. 可以用dp[i][0]记录 πdp[son][0] 最后判颜色+dp[i][1]
  47. dp[i][1]则记录 Σdp[son1][1]* πdp[son(不含son1)][0]
  48. 递推做到On
  49. 我们用a,b,c,d表示儿子节点,如果只有a,b,c,式子为:
  50. a1 * b2 * c2 + a2 * b1 * c2 + a2 * b2 * c1
  51. 加入d后:
  52. (a1 * b2 * c2 + a2 * b1 * c2 + a2 * b2 * c1) *d2 + a2 * b2 * c2 * d1
  53. 其中a2 * b2 * c2可直接用dp[i][0]递推过程值更新
  54.  
  55. */
  56.  
  57. void dfs(int u)
  58. {
  59. b[u] = ;
  60. register int size = , sum = , sum2 = , ok = ;
  61. dp[][u] = ;
  62. for(register int pos = head[u];pos;pos = edge[pos].next)
  63. {
  64. int v = edge[pos].v;
  65. if(b[v])continue;
  66. fa[v] = u;
  67. ++ size;
  68. ok = ;
  69. dfs(v);
  70. dp[][u] = ((long long)dp[][u] * dp[][v]) % MOD;
  71. dp[][u] += ((long long)dp[][u] * dp[][v]) % MOD;
  72. if(dp[][u] >= MOD)dp[][u] -= MOD;
  73. dp[][u] = ((long long)dp[][u] * dp[][v]) % MOD;
  74. }
  75. if(ok)
  76. {
  77. if(color[u]) dp[][u] = , dp[][u] = ;
  78. else dp[][u] = , dp[][u] = ;
  79. return;
  80. }
  81. if(color[u]) dp[][u] = dp[][u];
  82. else
  83. {
  84. dp[][u] += dp[][u];
  85. if(dp[][u] >= MOD)dp[][u] -= MOD;
  86. }
  87. return;
  88. }
  89.  
  90. int main()
  91. {
  92. read(n);
  93. register int tmp1;
  94. for(register int i = ;i < n - ;++ i) read(tmp1), insert(i + , tmp1 + ), insert(tmp1 + , i + );
  95. for(register int i = ;i < n;++ i) read(color[i + ]);
  96. dfs();
  97. printf("%d", dp[][]);
  98. return ;
  99. }

T3

NOIP模拟 17.8.15的更多相关文章

  1. NOIP模拟17.9.21

    NOIP模拟17.9.21 3 58 145 201 161.5 样例输出21.6 数据规模及约定对于40% 的数据,N <= 20对于60% 的数据,N <= 1000对于100% 的数 ...

  2. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  3. NOIP模拟 17.8.20

    NOIP模拟17.8.20 A.阶乘[题目描述]亲爱的xyx同学正在研究数学与阶乘的关系,但是他喜欢颓废,于是他就制作了一个和阶乘有关系的数学游戏:给出两个整数 n,m,令 t = !n,每轮游戏的流 ...

  4. NOIP模拟 17.8.18

    NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也 ...

  5. NOIP模拟 17.8.16

    NOIP模拟17.8.16 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...

  6. NOIP模拟 17.8.17

    NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 ...

  7. NOIP模拟 17.8.14

    NOIP模拟17.8.14 (天宇哥哥考察细心程度的题) [样例解释]如果删去第一个 1:在[3,1,2]中有 3 个不同的数如果删去 3:在[1,1,2]中有 2 个不同的数如果删去第二个 1:在[ ...

  8. NOIP模拟 17.9.28

    公交车[问题描述]市内有

  9. Noip模拟17 2021.7.16

    我愿称这场考试为STL专练 T1 世界线 巧妙使用$bitset$当作vis数组使用,内存不会炸,操作还方便,的确是极好的. 但是这个题如果不开一半的$bitset$是会炸内存的,因为他能开得很大,但 ...

随机推荐

  1. idea展示runDashboard的窗口

    一.idea的runDashboard打开workspace.xml文件之后,找到component为RunDashboard的节点处,然后在component标签里添加<option name ...

  2. 微信小程序——tab导航栏

    wxml: <view class="tab">  <view class="tab-left" bindtap="tabFun&q ...

  3. java基础之异常。

    异常: (1)异常:异常就是Java程序在运行过程中出现的错误. 异常由来:问题也是现实生活中一个具体事务,也可以通过java 的类的形式进行描述,并封装成对象.其实就是Java对不正常情况进行描述后 ...

  4. PHP基于openssl实现的非对称加密操作

    使用非对称加密主要是借助openssl的公钥和私钥,用公钥加密私钥解密,或者私钥加密公钥解密. 1.安装openssl和php的openssl扩展 2.生成私钥:openssl genrsa 用于生成 ...

  5. log4j 配置文件参数说明

    log4j 框架配置文件常用参数说明 %d 时间(-- ::,) %-5p 日志级别(INFO/DEBUG) %10c 包名(com.xxx.xxx.business.logging) %M 执行的方 ...

  6. 2019-7-2-Roslyn-开发-NuGet-包的-Task-编译可能遇到的问题

    title author date CreateTime categories Roslyn 开发 NuGet 包的 Task 编译可能遇到的问题 lindexi 2019-07-02 10:43:2 ...

  7. JQuery学习:jquery对象和js对象区别和转换

    JQuery对象与JS对象区别与转换 1.JQuery对象在操作时,更加方便 2.JQuery对象和js对象方法不通用 3.两者相互转换 *  jq -- > js:jq对象[索引]  或者  ...

  8. 入门servlet:request获取请求头数据

    @WebServlet("/RequestDemo2") public class RequestDemo2 extends HttpServlet { protected voi ...

  9. Rabbitmq交换机三种模式介绍

    1.topic 将路由键和某模式进行匹配.此时队列需要绑定要一个模式上.符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词.因此“abc.#”能够匹配到“abc.def.ghi”,但是“abc. ...

  10. 批量操作文本文件进行dos/unix格式转换

    批量将目录下所有文件进行 dos/unix 格式转换 使用 sed + grep #sed -i "s/原字符串/新字符串/g" `grep 原字符串 -rl 所在目录` eg:  ...