upd:2019-12-20

题目源自codeforces的Round_551

Round_551/F:

牛逼的dp

upd:2019-12-14

题目源自codeforces的Round_552

Round_552/F:

这个题一开始按照背包的经典dp转移去写,外面枚举物品,里面枚举状态,就WA

仔细思考之后发现这个问题里,把sp offer看作背包问题中的物品

两个不同物品放入背包的先后顺序,对答案是有影响的

为了避免这种影响,应该外层枚举状态,内层枚举物品。这样就可了

Round_552/G:

智力题。先处理两个数相同 lcm(x, x)  = x的情况。然后再做下面。

假设ai和aj为最优解,那么有g=gcd(ai, aj)

枚举g,找到g的倍数中在a里出现过的最小的两个不同数x*g和y*g,用x*y*g更新答案即可

由于我们枚举g从1-1e7,所以一定能够枚举到gcd(ai, aj),此时最优解一定会更新答案,所以保证正确

upd:2019-12-13

题目源自codeforces的Round_602_div1+2, Round_603_div2, Educational_Round_77

Round_603/F:

考虑一个经典dp状态定义, dp[i][j]代表上面一个树的最后一个被选取的叶节点编号是i

下面的树最后一个被选取的叶节点编号是j且 i != j

那么我们需要考虑第 max(i, j) + 1 个点是选择上下哪棵树的点

这个代价其实就是比较好求的了

Round_602_div1/E:

我直接参考的最短的代码

一个比较牛逼的构造,正确性自己手画一下是可以证明的

我先证明了相邻两行必然不等,然后证明的 1 <= i < j <= n 必有第i行和第j行不等

然后证明1 <= i <= n 必有第i行和第 n+1 行不等

Round_603_div1/F:

一个比较牛逼的分治

Educational_Round_77/F:

一个比较牛逼的树上计数

upd:2018-11-25

题目源自codeforeces的三场contest

contest/1043+1055+1076

目前都是solved 6/7,都差了最后一题

简单题:

contest/1043/E:

先不考虑m个限制,求出每个人与其他所有人组队的情况下这个人获得的分数

对于当前的 i ,如果他与 j 组队时 i 做第一题,则有 xi + yj <= xj + yi

即 xi - yi <= xj - yj,排序累加计算即可

contest/1055/C:

注意到 la 与 lb 的差距会由于 t0 和 t1 而变化 k*gcd(t0, t1), k为系数

所以肯定想让 la 和 lb 离得尽量近,重合部分也就越大

能让两个位置重合就重合,不能重合就在那个位置前后蹭蹭就行了

contest/1076/D:

考虑最短路的dij算法,发现那些在最短路上的边形成了一棵树

所以直接跑堆优化dij

contest/1076/E:

kdtree模板题,变成二维空间操作,一维dep,一维dfn

二维空间矩形加+单点查询?考虑差分变为,单点加+前缀和

查询是在所有操作完成后,所以直接把操作和查询混在一起

按照第一关键字x,第二关键字y排序,排序后直接树状数组维护即可

O(nlogn)

思维僵化,有个O(n)做法,使用差分数组 f[ ]

把每个操作(v, d, x)挂到节点 v 上

然后一遍dfs,在到达v的时候对于节点上每个操作

f[dep[v]] += x, f[dep[v] + d + 1] -= x

dfs 回到点 v 父亲之前再做逆操作

对f[ ]求[1, dep[u]]的前缀和即为点 u 的答案

我傻逼了好久的题目:

contest/1055/D:

先对于那些w[i] != v[i]的所有串

求出他们共同的核心替换部分(必须替换并且长度一致)

然后为了不让无辜串也被替换所以要尝试将该串尽量向左右拓展

最后求出来替换串 s -> t 之后再验证,验证一开始想的太简单了

w[i] = v[i]的串,都满足w[i].find(s) == 0是不足够的

还会有别的情况!

简单暴力就是对n个串w[i]都find一下s,第一次找到就替换成 t

然后新串与v[i]对比即可

  1. #include <bits/stdc++.h>
  2.  
  3. #define lb(x) (x&(-x))
  4.  
  5. typedef long long ll;
  6.  
  7. using namespace std;
  8.  
  9. const int N = ;
  10.  
  11. string s = "", t;
  12.  
  13. int n, flag[N];
  14.  
  15. string a[N], b[N];
  16.  
  17. int nex[N], l[N], r[N];
  18.  
  19. vector <int> lt;
  20.  
  21. void calc_next() {
  22. nex[] = -;
  23. for (int i = ; i < s.size(); i ++) {
  24. int j = nex[i - ];
  25. while (j != - && s[j + ] != s[i]) j = nex[j];
  26. if (s[j + ] == s[i]) nex[i] = j + ;
  27. else nex[i] = -;
  28. }
  29. }
  30.  
  31. void kmp(string &st) {
  32. for (int i = , j = -; i < st.size(); i ++) {
  33. while (j != - && s[j + ] != st[i]) j = nex[j];
  34. if (s[j + ] == st[i]) {
  35. j ++;
  36. if (j + == s.size()) {
  37. st = st.substr(, i + - s.size()) + t + st.substr(i + );
  38. return;
  39. }
  40. }
  41. }
  42. }
  43.  
  44. int main() {
  45. ios::sync_with_stdio(false);
  46. cin >> n;
  47. for (int i = ; i <= n; i ++) cin >> a[i];
  48. for (int i = ; i <= n; i ++) cin >> b[i];
  49. for (int i = ; i <= n; i ++) {
  50. l[i] = -, r[i] = -;
  51. for (int j = ; j < a[i].size(); j ++) {
  52. if (a[i][j] != b[i][j]) {
  53. if (l[i] == -) l[i] = j;
  54. r[i] = j;
  55. }
  56. }
  57. if (l[i] == -) continue;
  58. if (s == "") s = a[i].substr(l[i], r[i] - l[i] + ), t = b[i].substr(l[i], r[i] - l[i] + );
  59. else if (s != a[i].substr(l[i], r[i] - l[i] + ) || t != b[i].substr(l[i], r[i] - l[i] + )) {
  60. cout << "NO";
  61. return ;
  62. }
  63. lt.push_back(i);
  64. }
  65. while () {
  66. int flag = ;
  67. for (int i : lt) {
  68. l[i] --;
  69. if (l[i] < ) {
  70. flag = ;
  71. break;
  72. }
  73. }
  74. if (!flag) break;
  75. char ch = a[lt[]][l[lt[]]];
  76. for (int i : lt) {
  77. if (ch != a[i][l[i]]) {
  78. flag = ;
  79. break;
  80. }
  81. }
  82. if (!flag) break;
  83. s = ch + s;
  84. t = ch + t;
  85. }
  86. while () {
  87. int flag = ;
  88. for (int i : lt) {
  89. r[i] ++;
  90. if (r[i] >= a[i].size()) {
  91. flag = ;
  92. break;
  93. }
  94. }
  95. if (!flag) break;
  96. char ch = a[lt[]][r[lt[]]];
  97. for (int i : lt) {
  98. if (ch != a[i][r[i]]) {
  99. flag = ;
  100. break;
  101. }
  102. }
  103. if (!flag) break;
  104. s += ch;
  105. t += ch;
  106. }
  107. calc_next();
  108. for (int i = ; i <= n; i ++) {
  109. kmp(a[i]);
  110. if (a[i] != b[i]) {
  111. cout << "NO";
  112. return ;
  113. }
  114. }
  115. cout << "YES\n" << s << '\n' << t;
  116. return ;
  117. }

其他题目:

contest/1055/F:

树上异或路径和,把每个点的权值变为到根的异或路径和

异或路径和就变为了两点的权值异或和

这个题如果问有多少条路径异或和<=x

就可以直接树分治+trie树,O(nlogn^2)

但是问排名为k的,套个二分O(nlogn^3),gg

直接在trie树上搞,从高到低考虑当前位取0的结果个数

超过了k,则ans当前位取0,否则当前位取1

空间O(62*n)会爆MLE,直接一层一层的构建trie树

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. const int N = 2e6 + ;
  6.  
  7. int cnt, t, sz[N];
  8.  
  9. int n, a[N], b[N], ch[N][];
  10.  
  11. long long s, k, ans, v[N];
  12.  
  13. int pos(int x, int y) {
  14. return ch[x][y] ? ch[x][y] : ch[x][y] = ++ cnt;
  15. }
  16.  
  17. int main() {
  18. ios::sync_with_stdio(false);
  19. cin >> n >> k;
  20. for (int p, i = ; i <= n; i ++)
  21. cin >> p >> v[i], v[i] ^= v[p];
  22. for (int i = ; i <= n; i ++)
  23. a[i] = b[i] = ;
  24. for (int j = ; ~j; j --) {
  25. for (int i = ; i <= cnt; i ++) ch[i][] = ch[i][] = sz[i] = ;
  26. s = t = cnt = ;
  27. for (int i = ; i <= n; i ++) sz[a[i] = pos(a[i], v[i] >> j & )] ++;
  28. for (int i = ; i <= n; i ++) s += sz[ch[b[i]][v[i] >> j & ]];
  29. if (s < k) ans |= 1ll << j, k -= s, t = ;
  30. for (int i = ; i <= n; i ++) b[i] = ch[b[i]][(v[i] >> j & ) ^ t];
  31. }
  32. cout << ans;
  33. return ;
  34. }

几个DP题目:

contest/1043/F:

给出n个数,问最少选几个数可以使得gcd=1

考虑最优解集合,先拿出第一个数

然后依次拿出其他数跟它求gcd,那么gcd一定是逐次减小的

并且每次约去的质因数都是不同的(不然这个数没有意义不会出现在最优集合里)

ai <= 3e5,可以求出ans如果存在一定 ans <= 7

设计dp[i][j]代表去除 i 个不同数字使得他们gcd为 j 的方案数有多少种

i 从小到大枚举, for i 1 -> 7

dp[i][j] 考虑容斥求出,取 i 个数的gcd为 j 的倍数的方案数

减去 gcd 为 j*2, j*3, j*4 的方案数即为我们需要的方案数了

dp[i][1] != 0,则取 i 个数能 gcd = 1

O(k*nlogn),k为系数,最大是 7

考虑中间需要组合数,而C(n,  7)会爆long long

但注意到我们的不需要结果的具体方案数,只想知道dp[i][1] != 0

所以考虑直接模大质数即可,自然溢出也可以

再不相信就直接取两个大质数跑两次验证

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. const int N = 3e5 + ;
  6.  
  7. const int Mod = 1e9 + ;
  8.  
  9. int n, m, a[N], b[N];
  10.  
  11. int c[N], dp[N], cnt[N];
  12.  
  13. int main() {
  14. ios::sync_with_stdio(false);
  15. cin >> n;
  16. for (int i = ; i <= n; i ++)
  17. cin >> a[i], m = max(m, a[i]), b[a[i]] ++;
  18. for (int i = ; i <= m; i ++) {
  19. for (int j = i; j <= m; j += i)
  20. cnt[i] += b[j];
  21. c[i] = ;
  22. }
  23. for (int k = ; k < ; k ++) {
  24. for (int i = m; i; i --) {
  25. dp[i] = (c[i] = 1ll * c[i] * (cnt[i] + - k) % Mod);
  26. for (int j = i << ; j <= m; j += i)
  27. dp[i] = (dp[i] - dp[j]) % Mod;
  28. }
  29. if (dp[] != ) {
  30. printf("%d\n", k);
  31. return ;
  32. }
  33. }
  34. puts("-1");

contest/1055/E:

这题面有毒啊,应该用set不是multiset啊

直接二分答案x进行验证

是否可以取出m个区间,使得m个区间组成的set里<=x的数字>=k个

dp[i][j]代表假设总区间只有[1, i]

选择了 j 个区间后,最多能包含多少个<=x的数字  

枚举 i, 考虑dp[i][j],只有包含 i 和不包含 i

不包含 i -> dp[i - 1][j]

包含 i, 找到所有包含i的区间里最小的左端点L -> dp[L - 1][j - 1] + count(ai <= x for i in [L, i])

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. const int N = ;
  6.  
  7. int n, m, s, k;
  8.  
  9. int a[N], l[N], r[N], dp[N][N];
  10.  
  11. bool check(int x) {
  12. memset (dp, , sizeof dp);
  13. for (int i = ; i <= n; i ++) {
  14. int pos = i + , sum = ;
  15. for (int j = ; j <= s; j ++)
  16. if (l[j] <= i && i <= r[j])
  17. pos = min(pos, l[j]);
  18. for (int j = pos; j <= i; j ++)
  19. sum += a[j] <= x;
  20. for (int j = ; j <= m; j ++)
  21. dp[i][j] = max(dp[i - ][j], dp[pos - ][j - ] + sum);
  22. }
  23. return dp[n][m] >= k;
  24. }
  25.  
  26. int main() {
  27. ios::sync_with_stdio(false);
  28. int L = 1e9, R = , mid, ans = -;
  29. cin >> n >> s >> m >> k;
  30. for (int i = ; i <= n; i ++)
  31. cin >> a[i], L = min(L, a[i]), R = max(R, a[i]);
  32. for (int i = ; i <= s; i ++)
  33. cin >> l[i] >> r[i];
  34. while (L <= R) {
  35. if (check(mid = L + R >> )) ans = mid, R = mid - ;
  36. else L = mid + ;
  37. }
  38. cout << ans;
  39. return ;
  40. }

contest/1076/F:

dp[i][j]代表第 i 页以 type j 结尾的话,最少结尾是几个连续的type j

因为考虑当前页以type x结尾的话

如果下一页的全局最优答案是以type x开始的话,那肯定希望当前页结尾的x越少越好

如果不是type x开始的话,那么当前页只要以x结尾,多少个都无所谓啦

所以我们需要这个状态!

min(dp[n][0], dp[n][1])即为答案

转移就贪心转移

  1. #include <bits/stdc++.h>
  2.  
  3. #define lb(x) (x&(-x))
  4.  
  5. using namespace std;
  6.  
  7. const int N = 3e5 + ;
  8.  
  9. typedef long long ll;
  10.  
  11. ll n, k, a[N][], dp[N][];
  12.  
  13. int main() {
  14. ios::sync_with_stdio(false);
  15. cin >> n >> k;
  16. for (ll i = ; i <= n; i ++) cin >> a[i][];
  17. for (ll i = ; i <= n; i ++) cin >> a[i][];
  18. for (ll s0, min0, s1, min1, i = ; i <= n; i ++) {
  19. dp[i][] = dp[i][] = k + ;
  20. if (dp[i - ][] <= k) {
  21. s0 = dp[i - ][] + a[i][];
  22. min1 = (s0 + k - ) / k - ;
  23. if (a[i][] >= min1 && a[i][] <= (a[i][] + ) * k) {
  24. if (a[i][] == min1) dp[i][] = min(dp[i][], s0 - k * min1);
  25. else if (a[i][] > a[i][] * k) dp[i][] = min(dp[i][], a[i][] - a[i][] * k);
  26. else dp[i][] = dp[i][] = ;
  27. }
  28. }
  29. if (dp[i - ][] <= k) {
  30. s1 = dp[i - ][] + a[i][];
  31. min0 = (s1 + k - ) / k - ;
  32. if (a[i][] >= min0 && a[i][] <= (a[i][] + ) * k) {
  33. if (a[i][] == min0) dp[i][] = min(dp[i][], s1 - k * min0);
  34. else if (a[i][] > a[i][] * k) dp[i][] = min(dp[i][], a[i][] - a[i][] * k);
  35. else dp[i][] = dp[i][] = ;
  36. }
  37. }
  38. }
  39. cout << (dp[n][] <= k || dp[n][] <= k ? "YES" : "NO");
  40. return ;
  41. }

codeforeces近日题目小结的更多相关文章

  1. 【Mark】博弈类题目小结(HDU,POJ,ZOJ)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 首先当然要献上一些非常好的学习资料: 基础博弈的小 ...

  2. ACM - 概率、期望题目 小结(临时)

    概率DP求期望大多数都是全期望公式的运用.主要思考状态空间的划分以及状态事件发生的概率.问题可以分为无环和有环两类.无环一类多数比较简单,可以通过迭代或者记忆化搜索完成.有环一类略复杂,可以通过假设方 ...

  3. ACM -二分图题目小结

    暂时只包括与最大匹配相关的问题. 求最大独立集,最小路径覆盖等等大多数题目都可以转化为求最大匹配用匈牙利算法解决. 1.最大匹配(边集) 此类问题最直接,直接用匈牙利算法即可. HDU 2063  过 ...

  4. CDQ分治题目小结

    CDQ分治属于比较特殊的一类分治,许多问题转化为这类分治的时候,时空方面都会有很大节省,而且写起来没有这么麻烦. 这类分治的特殊性在于分治的左右两部分的合并,作用两部分在合并的时候作用是不同的,比如, ...

  5. ACM - KMP题目小结 (更新中)

    KMP算法题型大致有两类,一类是next数组的应用,一类是匹配问题. next数组大多数是求字符串周期,或者是与前缀后缀有关,也可以应用在DP中.需要对next数组有一定理解才能做得出. next数组 ...

  6. 前端笔试题目小结--获取输入参数用户名;查询URL字符串参数

    编写一个JavaScript函数getSuffix,用于获得输入参数的后缀名.如输入abc.txt,返回txt. str1 = "abc.txt"; function getSuf ...

  7. leetcode数组典型题目小结

    数组与矩阵 数组与矩阵的基本知识: 1.数组:数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式. 首先,数组会利用索引来记录每个元素在数组中的位置,且在大多数 ...

  8. poj 题目分类(1)

    poj 题目分类 按照ac的代码长度分类(主要参考最短代码和自己写的代码) 短代码:0.01K--0.50K:中短代码:0.51K--1.00K:中等代码量:1.01K--2.00K:长代码:2.01 ...

  9. POJ题目分类(按初级\中级\高级等分类,有助于大家根据个人情况学习)

    本文来自:http://www.cppblog.com/snowshine09/archive/2011/08/02/152272.spx 多版本的POJ分类 流传最广的一种分类: 初期: 一.基本算 ...

随机推荐

  1. 织梦dedecms标签大全总结

    织梦dedecms标签大全总结,同时还建议多参考dede默认模板,织梦默认模板上的标签还是很有参考价值的. dedecms系统参数全局标签,在后台系统设置里可以看到这个参数 网站名称:{dede:gl ...

  2. 0619-dedeCMS数据表

    CMS的层级从前台分主要分为首页--栏目页--内容页,从后台分主要是四张表之间的关系: 1.模型表--dede_channeltype(顶级) 2.栏目表--dede_arctype 3.数据表:分为 ...

  3. JavaScript学习五

    2019-06-02 09:53:42

  4. Boost(1.69.0) windows入门(译)

    目录 Boost windows入门 1. 获得Boost源代码 2. Boost源代码组织 The Boost Distribution 3. 仅用头文件的库 Header-Only Librari ...

  5. Ansible+Jenkins+Gitlab搭建及配置

    Ansible+Jenkins+Gitlab搭建及配置,已经生产环境使用,运行良好. 主机组文件里面好多ip敏感信息就不写了

  6. BZOJ 2946 SA/SAM

    思路: 1. 二分+后缀数组 2.SAM //By SiriusRen #include <cstdio> #include <cstring> #include <al ...

  7. Codeforces 763A

    乍看之下感觉有点无从下手,,其实是个很简单的水题,陷入僵局 题目大意:给一棵树,树上每个节点都染色,问能否取下一个节点,使得剩余所有子树上的点的颜色都相同.能输出YES和取下的节点编号,否则输出NO. ...

  8. [Luogu 1312] noip11 Mayan游戏

    [Luogu 1312] noip11 Mayan游戏 Problem: Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即 ...

  9. wordpress登录账号之后才能查看页面,实例

    函数: <?php auth_redirect(); ?> 例子: 要求用户登录才能查看页面 if(!is_user_logged_in()){ auth_redirect(); } 源文 ...

  10. 深入浅出的 SQL Server 查询优化

    目前网络数据库的应用已经成为最为广泛的应用之一了,并且关于数据库的安全性,性能都是企业最为关心的事情.数据库渐渐成为企业的命脉,优化查询就解决了每个关于数据库应用的性能问题,在这里microsoft ...