比赛链接

https://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206

这次考试的题非常有质量

这次考试暴露了非常多的问题,心理给自己设限,知识点不熟练等等问题。

只拿了暴力的分。

奈芙莲的护符

Nephren 有n个护符,每个护符的魔力容量都是无限的,并且每个护符在初始时已经被倾注了一些魔力。Nephren想要获得里面所有的魔力,但是她最后只能选择k个护符吸收。

所以,她需要将一些护符的魔力融合到一起。但是把i号护符的魔力移动到j号杯子需要花费c[i][j]的体力。

所以请您求出最小花费的体力。

【数据范围】

40%的数据保证n<=10。

100%的数据保证1≤ k≤ n ≤ 20

所有的c[i][j]<=100000,c[i][i]=0.

Input
  1. 第一行,输入nk
  2. 下面N行,每行N个整数,描述c[i][j].
Output
  1. 输入一个整数,即所需的最小体力值。
Input示例
  1. 3 3 
  2. 0 1 1 
  3. 1 0 1 
  4. 1 1 0
Output示例
  1. 0

  1.  

这道题复习状压dp,状压dp一般可以处理一个集合内的问题

这道题是第三题,但我放在这一题

因为这一题反而最水……

我当时一看到数据范围20,马上想到状压dp

但是一方面因为觉得这是第三题,应该会比较难,而且前面两道题都做不出来,所以心理障碍

很大,就没有怎么很深入的去想(不过说到底还是状压dp不熟练)。

考完后,5分钟秒了,发现这是我做过最水的状压dp题。

这道题和TSP问题很类似(不懂的可以百度一下,或者我博客里面有)

用1表示魔力还在,0表示没有了。

那么dp[S] = min(dp[S], dp[S^(1<<j)] + c[j][i])

  1. #include<bits/stdc++.h>
  2. #define REP(i, a, b) for(register int i = (a); i < (b); i++)
  3. #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
  4. using namespace std;
  5.  
  6. const int MAXM = ( << ) + ;
  7. const int MAXN = ;
  8. int c[MAXN][MAXN], dp[MAXM];
  9.  
  10. int num(int x) { return !x ? : + num(x & (x - )); } //二进制中1的个数
  11.  
  12. int main()
  13. {
  14. int n, k;
  15. scanf("%d%d", &n, &k);
  16. REP(i, , n)
  17. REP(j, , n)
  18. scanf("%d", &c[i][j]);
  19.  
  20. int ans = 1e9;
  21. memset(dp, 0x3f, sizeof(dp)); //这里初始化要注意
  22. dp[(<<n)-] = ;
  23.  
  24. for(register int S = ( << n) - ; S >= ; S--)
  25. {
  26. if(num(S) < k) continue;
  27. REP(i, , n) if(S & ( << i))
  28. REP(j, , n) if(!(S & ( << j)))
  29. dp[S] = min(dp[S], dp[S^(<<j)] + c[j][i]);
  30. if(num(S) == k) ans = min(ans, dp[S]);
  31. }
  32. printf("%d\n", ans);
  33.  
  34. return ;
  35. }

珂朵莉的旅行

浮游大陆由n个浮游岛构成,其中不同的浮游岛之间存在着飞艇航线。

由于浮游大陆的经济比较紧张,花在交通的费用不能太多,因此在保证每一个浮游岛都是联通的基础上,大贤者只修筑了n-1条航线。

在击败第五号岛的兽之后,威廉决定带辛苦战斗的珂朵莉,奈芙莲,艾瑟雅去浮游大陆旅行。

“Are you going toScarborough Fair?”

每个浮游岛本质属于不同的政体,所以它们的政策等会存在诸多差异。在旅行之前,威廉将浮游岛划分成两种,可以认为权值为1和0.由于要保证这是一次开心的旅行,所以他希望旅行之后经过的路径浮游岛的权值异或和为0.

他们的旅行方案是这样的:从某一个节点开始,不经过重复的节点,随机的选择一个与当前节点相连的节点,直到走到无路可走,这算完成一次旅行。

由于威廉也才来到浮游大陆不久,所以他也不知道每一个节点的权值到底是1还是0.

他想问问你,总共有多少种可能的钦点某些浮游岛的权值为1(其他浮游岛权值为0)的方式,符合上文提出的条件?

由于他们没有学过数学,因此请你将答案对 109+7 (一个质数)取模。

【数据规模和约定】

对于20%的数据,满足1<=n<=10

对于40%的数据,满足1<=n<=1000

对于额外20%的数据,浮游岛的连接将会成为一条链。

对于100%的数据,1<=n<=10^6.

【样例解释】

如果威廉选择从1号浮游岛出发,那么可以设置0个或者2个浮游岛权值为1,因此共有4种可能。如果威廉选择从2号浮游岛出发,他可以走2-1,或者2-3,因此他可以设置0个浮游岛权值为1,或者三个浮游岛权值全部为1.从3出发和从1出发情况类似,因此共有4+2+4=10种方案。
Input
  1. 第一行一个整数n,表示浮游岛的数量
  2. 第二行开始每行两个整数u,v,表示浮游岛u和浮游岛v有无向的飞艇路线相连。
Output
  1. 一行一个整数,表示答案。
Input示例
  1. 3
  2. 1 2
  3. 2 3
Output示例

  1. 10

  1. 关于异或和,如果1的个数是偶数,那就是0,如果是奇数,就是1,和0取异或就不变,和1取异或就取反
    n方的数据可以用树形dp
    我考试的时候dp方程都推出来了,可是竟然没有写,觉得是错的(我到底在干嘛???)(树形dp不熟练
    dp[i][0]表示从子树到子树根的路径异或和0的方案数,dp[i][1]是异或和为1
    如果是dp[i][0]
    如果根为1,那么除根以外的路径就要异或和为1,同时根据乘法原理,
    方案数是dp[v1][1] * dp[v2][1]……
    如果根为0,那么除根以外的路径就要异或和为0,同时根据乘法原理,
    方案数是dp[v1][1] * dp[v2][1]……
    然后根据加法原理,把这两个加起来
    所以dp[i][0] = dp[v1][1] * dp[v2][1]……)+(dp[v1][1] * dp[v2][1]……)
    dp[i][1]也类似,然后可以发现是一样的
    dp[i][1] = dp[v1][1] * dp[v2][1]……)+(dp[v1][1] * dp[v2][1]……)
  2.  
  3. 但是不知道为什么只过了2个点,会RE2个点
  1. #include<bits/stdc++.h>
  2. #define REP(i, a, b) for(register int i = (a); i < (b); i++)
  3. #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
  4. using namespace std;
  5.  
  6. typedef long long ll;
  7. const int MAXN = 1e6 + ;
  8. const int mod = 1e9 + ;
  9.  
  10. struct Edge{ int to, next; };
  11. Edge e[MAXN << ];
  12. int head[MAXN], tot;
  13.  
  14. int d[MAXN], n;
  15. ll dp[MAXN][];
  16.  
  17. void read(int& x)
  18. {
  19. int f = ; x = ; char ch = getchar();
  20. while(!isdigit(ch)) { if(ch == '-') f = -; ch = getchar(); }
  21. while(isdigit(ch)) { x = x * + ch - ''; ch = getchar(); }
  22. x *= f;
  23. }
  24.  
  25. void AddEdge(int from, int to)
  26. {
  27. e[tot] = Edge{to, head[from]};
  28. head[from] = tot++;
  29. }
  30.  
  31. void dfs(int u, int fa)
  32. {
  33. if(d[u] == && fa != -)
  34. {
  35. dp[u][] = dp[u][] = ;
  36. return;
  37. }
  38.  
  39. ll a = , b = ;
  40. for(int i = head[u]; ~i; i = e[i].next)
  41. {
  42. int v = e[i].to;
  43. if(v == fa) continue;
  44. dfs(v, u);
  45. a = a * dp[v][] % mod;
  46. b = b * dp[v][] % mod;
  47. }
  48.  
  49. dp[u][] = (dp[u][] + a + b) % mod;
  50. dp[u][] = (dp[u][] + a + b) % mod;
  51. }
  52.  
  53. int main()
  54. {
  55. read(n);
  56. if(n == ) { puts(""); return ; }
  57.  
  58. memset(head, -, sizeof(head)); tot = ;
  59.  
  60. REP(i, , n)
  61. {
  62. int u, v;
  63. read(u); read(v);
  64. AddEdge(u, v); AddEdge(v, u);
  65. d[u]++; d[v]++;
  66. }
  67.  
  68. ll ans = ;
  69. _for(i, , n)
  70. {
  71. memset(dp, , sizeof(dp));
  72. dfs(i, -);
  73. ans = (ans + dp[i][]) % mod;
  74. }
  75. printf("%lld\n", ans);
  76.  
  77. return ;
  78. }
  1. 然后我考虑20分一条链的做法
    其实这个部分分的做法再拓展一下就是满分做法了
    0-0-0-0-0-……0-0-0-0-0
    这是一条链
    我们分两部分来考虑,端点和除了端点以外的点
  2.  
  3. 如果是除了端点以外的点
    0-0-0-0-0-……0-0-0-0-0
    设总的点数为n,那么这样的点有n-2
    考虑其中一个点
    中间n-2个点的方案有2^(n-2)个
    对于其中一种方案
    其中一个点到端点之前的一个点的异或和是确定的
    那么端点的权值就是被动确定的
    比如从当前点到端点之前的一个点的异或和为0
    那么端点只能赋值为0,因为总的异或和为0
    所以端点的值是被动确定的。
    因此对于每一种方案,都可以通过调整端点的值来使得异或和
    0,且端点只有一种取值
    也就是说,2^(n-2)全部成立
    那么这只是对于其中一个点,那么对于n-2个点
    就有(n-2)*2^(n-2)种方案
  4.  
  5. 如果是端点
    分析方法类似
    对于其中一个端点,其他的点有2^(n-1)种方案
    端点本身被动确定
    那么有2个端点,也就是2*2^(n-1)方案
  6.  
  7. 最后加起来就好了
    2*2^(n-1) + n-2)*2^(n-2)
    = 2^(n-2) * (n+2)
  8.  
  9. 这就是20分的做法。
    其实我没想出来主要思维能力没有达到,还需要多做题
  10.  
  11. 100分的做法只是把端点的数变成叶子的数罢了
    推理的方式很像,把22个端点)换成kk个叶子)就好了
    所以答案为
    2^(n-k) * (n+k)
    读者可以自己推一遍(我懒)
  12.  
  13. 最后注意要特判一下n=1的情况,有点坑
  1. #include<bits/stdc++.h>
  2. #define REP(i, a, b) for(register int i = (a); i < (b); i++)
  3. #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
  4. using namespace std;
  5.  
  6. typedef long long ll;
  7. const int MAXN = 1e6 + ;
  8. const int mod = 1e9 + ;
  9. int d[MAXN], n;
  10.  
  11. void read(int& x)
  12. {
  13. int f = ; x = ; char ch = getchar();
  14. while(!isdigit(ch)) { if(ch == '-') f = -; ch = getchar(); }
  15. while(isdigit(ch)) { x = x * + ch - ''; ch = getchar(); }
  16. x *= f;
  17. }
  18.  
  19. ll pow(ll a, int b)
  20. {
  21. ll res = % mod; a %= mod;
  22. for(; b; b >>= )
  23. {
  24. if(b & ) res = res * a % mod;
  25. a = a * a % mod;
  26. }
  27. return res;
  28. }
  29.  
  30. int main()
  31. {
  32. read(n);
  33. if(n == ) { puts(""); return ; }
  34.  
  35. REP(i, , n)
  36. {
  37. int u, v;
  38. read(u); read(v);
  39. d[u]++; d[v]++;
  40. }
  41.  
  42. int k = ;
  43. _for(i, , n)
  44. if(d[i] == )
  45. k++;
  46.  
  47. ll ans = ;
  48. ans = pow(ans, n - k);
  49. ans = ans * (n + k) % mod;
  50. printf("%lld\n", ans);
  51.  
  52. return ;
  53. }

奈芙莲的序列

有一天可爱的Nephren得到了一个序列,一开始,她取出序列的第一个数,形成一个新的序列B,然后取出序列A的第二个数,放在序列B的最左边或最右边,序列B此时有两个数,下一步,再取出序列A的第三个数放在序列B的最左边或最右边,……

现在的问题是,通过上面的步骤,可以得到B的最长上升子序列的长度是多少

【数据规模及约定】

30%的数据保证N<=20

50%的数据保证N<=1000

100%的数据保证1 ≤ N ≤  2×105

保证a序列所有数不会超过 109

Input
  1. 第一行,一个整数N.
  2. 第二行,N个整数,表示序列A
Output
  1. 一行一个整数,表示最长上升子序列的长度
Input示例
  1. 4
  2. 2 1 3 4
Output示例
  1. 4

  1. 这道题的关键就是要推出一个性质,同时会用树状数组求LIS(二分的方法不行)
    什么性质呢?
    我们自己多造几组数据来算可以发现(然而我考试的时候并没有发现)
    新生成的b序列的最长上升子序列的长度>=a序列的最长上升子序列长度(我们要考虑原序列和新序列的关系)
    比如样例 2 1 3 4
    如果一直放最右边,那么生成的序列和原来一样
    那么我们可以通过某种策略来使新序列答案更大
    对于这道题,可以
    2
    1 2
    1 2 3
    1 2 3 4
    那么这种策略是什么呢,这是这道题的关键
    拿样例来看,为什么新生成序列答案更大
    答案中比原来序列的最长上升子序列多了一个1
    这个1怎么来的。
    原序列中在2的右边,然后放到2的左边来的。
    1满足在2的右边,又比2
    最长下降子序列???

    那么我们是不是可以猜一下
    新序列的最长上升子序列等于以a[i]为起始的最长上升子序列+a[i]为起始的最长下降子序列-1(多算了一次a[i])
    我们这么想
    先说最长上升子序列,我们可以把这一部分的数从左到右一直放到最右边,那么这一部分的数就是有效的
    然后是最长下降子序列,我们可以把这一部分的数从左到右一直放到最左边,那么这一部分的数也是是有效的
  2.  
  3. 比如 6 5 4 3 7 8 9
    那么就是
    6
    5 6
    4 5 6
    3 4 5 6
    3 4 5 6 7
    3 4 5 6 7 8
    3 4 5 6 7 8 9
    这个数据可能有点水,但是就算最长上升子序列和最长下降子序列有交叉,也是成立的。
    遇到了最长上升子序列中的数,就放最右边,下降就最左,其他的数无所谓
    那么上面那个结论就成立了,也就是新序列的最长上升子序列等于以a[i]为起始的最长上升子序列+a[i]为起始的最长下降子序列-1(多算了一次a[i])
    那么枚举a[i]求max就好了。
  4.  
  5. 那么这两个数组怎么求呢
    可以n方暴力,拿50
    100分要用树状数组
    不知道怎么用树状数组优化到nlogn的同学可以看我写的这篇博客
    https://www.cnblogs.com/sugewud/p/9823222.html
  6.  
  7. 然后这里有个细节,就是求最长上升的时候
    a[i]变成-a[i]
    但是下标要>=1
    所以改成m - a[i] + 1m为离散化后最大的数值)
    但是因为是严格上升,加入的时候要写成m - a[i] + 0
    这个时候下标就会为0
    所以改成m - a[i] + 2 加入的时候写m - a[i] + 1
  8.  
  1. #include<bits/stdc++.h>
  2. #define REP(i, a, b) for(register int i = (a); i < (b); i++)
  3. #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
  4. using namespace std;
  5.  
  6. const int MAXN = 2e5 + ;
  7. int a[MAXN], b[MAXN], n, m;
  8. int dp[MAXN][], f[MAXN];
  9.  
  10. inline lowbit(int x) { return x & (-x); }
  11.  
  12. void motify(int x, int p)
  13. {
  14. for(; x <= m + ; x += lowbit(x))
  15. f[x] = max(f[x], p);
  16. }
  17.  
  18. int get_max(int x)
  19. {
  20. int res = ;
  21. for(; x; x -= lowbit(x))
  22. res = max(res, f[x]);
  23. return res;
  24. }
  25.  
  26. int main()
  27. {
  28. scanf("%d", &n);
  29. _for(i, , n) scanf("%d", &a[i]), b[i] = a[i];
  30.  
  31. sort(b + , b + n + );
  32. m = unique(b + , b + n + ) - b - ;
  33. _for(i, , n) a[i] = lower_bound(b + , b + m + , a[i]) - b;
  34.  
  35. for(register int i = n; i >= ; i--)
  36. {
  37. dp[i][] = get_max(m - a[i] + ) + ;
  38. motify(m - a[i] + , dp[i][]);
  39. }
  40.  
  41. memset(f, , sizeof(f));
  42. for(register int i = n; i >= ; i--)
  43. {
  44. dp[i][] = get_max(a[i] - ) + ;
  45. motify(a[i], dp[i][]);
  46. }
  47.  
  48. int ans = ;
  49. _for(i, , n)
  50. ans = max(ans, dp[i][] + dp[i][] - );
  51. printf("%d\n", ans);
  52.  
  53. return ;
  54. }
  1.  
  2. 总结:收货还是蛮大的
    T1 思维方式+复习树形dp
    T2 手算样例找规律猜结论+学会树状数组求LIS
    T3 复习状压dp
  1.  

NOIP2018提高组省一冲奖班模测训练(一)的更多相关文章

  1. NOIP2018提高组省一冲奖班模测训练(六)

    NOIP2018提高组省一冲奖班模测训练(六) https://www.51nod.com/Contest/ContestDescription.html#!#contestId=80 20分钟AC掉 ...

  2. NOIP2018提高组省一冲奖班模测训练(五)

    NOIP2018提高组省一冲奖班模测训练(五) http://www.51nod.com/Contest/ContestDescription.html#!#contestId=79 今天有点浪…… ...

  3. NOIP2018提高组省一冲奖班模测训练(四)

    NOIP2018提高组省一冲奖班模测训练(四) 这次比赛只AC了第一题,而且花了40多分钟,貌似是A掉第一题里面最晚的 而且还有一个半小时我就放弃了…… 下次即使想不出也要坚持到最后 第二题没思路 第 ...

  4. NOIP2018提高组省一冲奖班模测训练(三)

    NOIP2018提高组省一冲奖班模测训练(三) 自己按照noip的方式考,只在最后一两分钟交了一次 第一题过了,对拍拍到尾. 第二题不会.考试时往组合计数的方向想,推公式,推了一个多小时,大脑爆炸,还 ...

  5. NOIP2018提高组省一冲奖班模测训练(二)

    比赛链接 NOIP2018提高组省一冲奖班模测训练(二) 今天发挥正常,昨天不在状态…… 花了很久A了第一题 第二题打了30分暴力 第三题投机取巧输出test1答案(连暴力都不知道怎么打,太弱了) 2 ...

  6. [51Nod]NOIP2018提高组省一冲奖班模测训练(三) 题解

    链接 A.Anan的派对 题意:Anan想举办一个派对.Anan的朋友总共有 n 人.第i个人如果参加派对会得到 \(c_i\) 的快乐值,除他自己外每多一个人参加他会减少 \(d_i\) 的快乐值. ...

  7. [51Nod]NOIP2018提高组省一冲奖班模测训练(四)翻车记+题解

    链接 下午5点的时候,突然想起来有这个比赛,看看还有一个小时,打算来AK一下,结果因为最近智商越来越低,翻车了,我还是太菜了.上来10分钟先切掉了C和A,结果卡在了B题,唉. A.砍树 一眼题,两遍树 ...

  8. [51Nod]NOIP2018提高组省一冲奖班模测训练(二)

    http://www.51nod.com/contest/problemList.html#!contestId=73&randomCode=4408520896354389006 还是原题大 ...

  9. [51Nod]NOIP2018提高组省一冲奖班模测训练(一)题解

    http://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 原题水题大赛.. A.珂朵莉的旅行 ...

随机推荐

  1. 深入理解JMM(Java内存模型) --(六)final

    与前面介绍的锁和volatile相比较,对final域的读和写更像是普通的变量访问.对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的写入,与随后把这个被构造对象 ...

  2. urllib2.urlopen超时未设置导致程序卡死

    没有设置timeout参数,结果在网络环境不好的情况下,时常出现read()方法没有任何反应的问题,程序卡死在read()方法里,搞了大半天,才找到问题,给urlopen加上timeout就ok了,设 ...

  3. 转贴:获取元素CSS值之getComputedStyle方法熟悉

    获取元素CSS值之getComputedStyle方法熟悉 一.碎碎念~前言 我们都用过jQuery的CSS()方法,其底层运作就应用了getComputedStyle以及getPropertyVal ...

  4. Permutations II 典型去重

    https://leetcode.com/problems/permutations-ii/ Given a collection of numbers that might contain dupl ...

  5. Spring的 @ExceptionHandler注解无效问题

    如果你想设置了@ExceptionHandler注解进行异常捕获返回异常信息,但是Debug调试时,代码并未进到被@ExceptionHandler注解标注的方法里,那么就检查你的配置文件是否包含 & ...

  6. restful api 错误

    简介 随着移动开发和前端开发的崛起,越来越多的 Web 后端应用都倾向于实现 Restful API.Restful API 是一个简单易用的前后端分离方案,它只需要对客户端请求进行处理,然后返回结果 ...

  7. codechef : TREDEG , Trees and Degrees

    其实有原题,生成树计数 然鹅这题里面是两道题, 50pts 可以用上面那题的做法直接过掉,另外 50pts 要推推式子,搞出 O n 的做法才行(毕竟多项式常数之大您是知道的) 虽说这道题里面是没有 ...

  8. JavaScript编程艺术-第7章代码汇总(2)

    [7.4节] 重回“JavaScript美术馆”代码 ***亲测可用*** HTML: JS:

  9. 二分图最大匹配(匈牙利算法) UVA 10080 Gopher II

    题目传送门 /* 匈牙利算法:这题比UVA_670简单,注意是要被吃的鼠的最少个数,套模板 */ #include <cstdio> #include <algorithm> ...

  10. VMWare虚拟网络编辑

    VMWare虚拟网络编辑记录. 点击"编辑->虚拟网络编辑器" 在网卡列表中选择"VMnet8"查看目前设置,点击右下角的更改设置进行网络修改. 备注:更 ...