A - Forgetting Things

题意:给 \(a,b\) 两个数字的开头数字(1~9),求使得等式 \(a=b-1\) 成立的一组 \(a,b\) ,无解输出-1。

题解:很显然只有 \(a=b\) 和 \(a=b-1\) 的时候有解,再加上一个从 \(9\) 越到 \(10\) 的就可以了。被样例的 \(199,200\) 误导了。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. int main() {
  5. #ifdef KisekiPurin
  6. freopen("KisekiPurin.in", "r", stdin);
  7. #endif // KisekiPurin
  8. int a, b;
  9. while(~scanf("%d%d", &a, &b)) {
  10. if(a == b)
  11. printf("%d %d\n", a * 10, b * 10 + 1);
  12. else if(a == b - 1)
  13. printf("%d %d\n", a, b);
  14. else if(a == 9 && b == 1)
  15. printf("9 10\n");
  16. else
  17. puts("-1");
  18. }
  19. }

B1 - TV Subscriptions (Easy Version)

见下一题

B2 - TV Subscriptions (Hard Version)

题意:有n天,每天上映一段电视剧的第ai节,要连续看d天,求最少买多少张票。注意买了某一节的票之后就可以反复看这一节。

题解:看数据量,是不是可以二分票的张数,然后尺取暴力验证呢?不过真的t会卡memset,而k的上限又没给,假如想用memset的话要先进行一次离散化。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. int n, k, d;
  5. int a[200005];
  6. int cnt[1000005];
  7. bool check(int m) {
  8. int cur = 0;
  9. for(int i = 1; i <= d; ++i) {
  10. ++cnt[a[i]];
  11. if(cnt[a[i]] == 1)
  12. ++cur;
  13. }
  14. if(cur <= m) {
  15. for(int i = 1; i <= d; ++i)
  16. cnt[a[i]] = 0;
  17. return 1;
  18. }
  19. for(int i = d + 1; i <= n; ++i) {
  20. ++cnt[a[i]];
  21. if(cnt[a[i]] == 1)
  22. ++cur;
  23. --cnt[a[i - d]];
  24. if(cnt[a[i - d]] == 0) {
  25. --cur;
  26. if(cur <= m) {
  27. for(int j = 0; j < d; ++j)
  28. cnt[a[i - j]] = 0;
  29. return 1;
  30. }
  31. }
  32. }
  33. for(int j = 0; j < d; ++j)
  34. cnt[a[n - j]] = 0;
  35. return 0;
  36. }
  37. int bs() {
  38. int l = 1, r = d, m;
  39. while(1) {
  40. m = (l + r) >> 1;
  41. if(l == m) {
  42. if(check(l))
  43. return l;
  44. return r;
  45. }
  46. if(check(m))
  47. r = m;
  48. else
  49. l = m + 1;
  50. }
  51. }
  52. int main() {
  53. #ifdef KisekiPurin
  54. freopen("KisekiPurin.in", "r", stdin);
  55. #endif // KisekiPurin
  56. int t;
  57. scanf("%d", &t);
  58. while(t--) {
  59. scanf("%d%d%d", &n, &k, &d);
  60. for(int i = 1; i <= n; ++i)
  61. scanf("%d", &a[i]);
  62. printf("%d\n", bs());
  63. }
  64. }

补题题解:其实并不需要二分,扫的时候就知道最小值是谁了。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. int n, k, d;
  5. int a[200005];
  6. int cnt[1000005];
  7. int solve() {
  8. int cur = 0;
  9. for(int i = 1; i <= d; ++i) {
  10. ++cnt[a[i]];
  11. if(cnt[a[i]] == 1)
  12. ++cur;
  13. }
  14. int mincur = cur;
  15. for(int i = d + 1; i <= n; ++i) {
  16. ++cnt[a[i]];
  17. if(cnt[a[i]] == 1)
  18. ++cur;
  19. --cnt[a[i - d]];
  20. if(cnt[a[i - d]] == 0) {
  21. --cur;
  22. if(cur < mincur)
  23. mincur = cur;
  24. }
  25. }
  26. for(int j = 0; j < d; ++j)
  27. cnt[a[n - j]] = 0;
  28. return mincur;
  29. }
  30. int main() {
  31. #ifdef KisekiPurin
  32. freopen("KisekiPurin.in", "r", stdin);
  33. #endif // KisekiPurin
  34. int t;
  35. scanf("%d", &t);
  36. while(t--) {
  37. scanf("%d%d%d", &n, &k, &d);
  38. for(int i = 1; i <= n; ++i)
  39. scanf("%d", &a[i]);
  40. printf("%d\n", solve());
  41. }
  42. }

C - p-binary

题意:给一个整数n,求它最少用多少个p-binary数组成,无解输出-1,p-binary数是指形如 \(2^x+p\) 的数,其中x非负。

题解:看了下样例,感觉就是不断的尝试减去p(记总共减去了cnt个p),然后判断新的n能不能被cnt个二进制位所表示。不过样例提示我们可以用多个相同的二进制位合成一个高位,所以只需要新的n的二进制位数量不超过cnt就可以了。不过这样做卡了一个数据就是n=101,p=50,这个是输出-1,我这样写输出2,原因是1并不能被2个二进制位表示,因为不能取x=-1,所以得到另一个启发就是k个二进制位能表示的下限就是k(k个1相加),上限是无穷,但是能表示的数必须不超过cnt个1。

为什么比cnt少的二进制位都可以构造呢?因为可以用两个小的组成一个大的来使得cnt变相减少1,而这种方法使用的下限就是cnt个1。

顺带提一下__builtin_popcount()这个函数,其他的不好用但是这个(以及__builtin_ctz()返回后导零的个数)还是不错的。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. int main() {
  5. #ifdef KisekiPurin
  6. freopen("KisekiPurin.in", "r", stdin);
  7. #endif // KisekiPurin
  8. int n, p;
  9. while(~scanf("%d%d", &n, &p)) {
  10. int cnt = 0;
  11. while(cnt < 40) {
  12. n -= p;
  13. if(n <= 0) {
  14. cnt = -1;
  15. break;
  16. }
  17. ++cnt;
  18. if(__builtin_popcount(n) <= cnt && n >= cnt)
  19. break;
  20. }
  21. if(cnt == 40)
  22. cnt = -1;
  23. printf("%d\n", cnt);
  24. }
  25. }

D - Power Products

题意:给 \(n\)(2e5)个1e5内的数和 \(k\) (100),求有多少个无序数对 \((i,j)\) 满足存在一个 \(x\) 使得 \(a_ia_j=x^k\) 成立。

题解:

很显然就是每种质因数都要是k的倍数,那么每个数要找的那个数是在模意义下面唯一的,一个暴力的做法是分解1e5内的质数,然后求出不超过1e5的这个质数的最高幂,很明显这个最高幂很快就收敛到只剩下1了,那么可以用一个next指针为[0,16](也就是log(2,1e5))的字典树来存储。这样到后面一般只有两条路可以走。问题在于由于质数过多深度太大。

一种简单的改进就是特判掉k=2的情况,然后质数的范围就真的缩小到sqrt(1e5),超过这个范围的质数最多只有一个,且出现以后不可能会和另一个数配出k>=3时的k的倍数。这样是大概只有65层的一个字典树。

那怎么特判掉k=2的情况呢?应该是存在同一个大质因数的放在一堆,然后堆内匹配。不存在任何大质因数的也是一堆,也是堆内匹配。

补题题解:

本质上是要找唯一配对的一个质因数幂次序列,使用字典树会导致单次修改要经历所有的质数。其实根据唯一分解定理,把这些质因数幂次序列转回去整数存储就可以了,不用搞这么复杂。直接把一个数映射到幂模k的另一个数,然后用map存下来就可以了。甚至不需要用map,他的补数也必须限制在1e5里面的,在找补数的时候注意溢出就可以(使用map的话,应该是可以连溢出都不用管,因为溢出之后大部分应该是找不到答案,应该没有概率说溢出之后绕回来到1e5内)。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int MAXAI = 1e5;
  5. int cnt[100005];
  6. int p[105], ptop;
  7. bool np[405];
  8. ll qpow(ll x, int n) {
  9. ll res = 1;
  10. while(n) {
  11. if(x > MAXAI)
  12. return -1;
  13. if(n & 1) {
  14. res = res * x;
  15. if(res > MAXAI)
  16. return -1;
  17. }
  18. x = x * x;
  19. //不能在这里判断x溢出,因为有可能这个x不会叠到res上
  20. n >>= 1;
  21. }
  22. return res;
  23. }
  24. int main() {
  25. #ifdef KisekiPurin
  26. freopen("KisekiPurin.in", "r", stdin);
  27. #endif // KisekiPurin
  28. for(int i = 2, c = sqrt(MAXAI); i <= c; ++i) {
  29. if(np[i])
  30. continue;
  31. p[++ptop] = i;
  32. for(int j = i + i; j <= c; j += i)
  33. np[j] = 1;
  34. }
  35. int n, k;
  36. scanf("%d%d", &n, &k);
  37. ll ans = 0;
  38. for(int i = 1, ai; i <= n; ++i) {
  39. scanf("%d", &ai);
  40. ll bi = 1, ci = 1;
  41. for(int j = 1; j <= ptop; ++j) {
  42. if(ai % p[j] == 0) {
  43. int ki = 0;
  44. while(ai % p[j] == 0) {
  45. ++ki;
  46. ai /= p[j];
  47. }
  48. ki %= k;
  49. if(ki) {
  50. //假如ki==0,那么k-ki==0,bi和ci都不会变化
  51. ci *= qpow(p[j], ki);
  52. if(bi != -1) {
  53. ll tmp = qpow(p[j], k - ki);
  54. if(tmp != -1) {
  55. bi *= tmp;
  56. if(bi > MAXAI)
  57. bi = -1;
  58. } else
  59. bi = -1;
  60. }
  61. }
  62. }
  63. }
  64. if(ai > 1) {
  65. ci *= ai;
  66. if(bi != -1) {
  67. ll tmp = qpow(ai, k - 1);
  68. if(tmp != -1) {
  69. bi *= tmp;
  70. if(bi > MAXAI)
  71. bi = -1;
  72. } else
  73. bi = -1;
  74. }
  75. }
  76. if(bi != -1)
  77. //当bi不溢出时,看看前面是不是已经统计了这个bi
  78. ans += cnt[bi];
  79. ++cnt[ci];
  80. }
  81. printf("%lld\n", ans);
  82. }

注:快速幂里面的溢出不是在x=x*x之后判断,因为有可能会有n>>=1之后n==0,也就是最后一步并不会让res叠上x。

标签:质因数分解

E - Rock Is Push

题意:一个n*m(2000*2000)的棋盘格,每次只能向右或向下走,求走到最右下的不同路径数.注意棋盘格上有石头,可以推动石头,也可以推动一串石头,但是不能把石头推出边界。

补题题解:很显然的一个dp,但是要怎么入手呢?先说一个显然的结论,就是当前行/列的石头只会影响你在这个行/列上前进的终点,在改变方向只会这些石头会再有没有用,所以说每次只需要考虑当前方向上的石头即可。

\(dp[i][j][0]\) 表示从左侧走到格子 \((i,j)\) 的方案数。

\(dp[i][j][1]\) 表示从上侧走到格子 \((i,j)\) 的方案数。

那么怎么转移呢?举个例子,比如现在求的是 \(dp[i][j][1]\) ,从上方进来的话,会有最后一次向右走的位置,记这个位置为 \((k,j)\) ,也就是从左侧进入了 \((k,j)\) ,然后一直往下到 \((i,j)\) ,什么是合法的 \((k,j)\) 呢?当然就是 \((k,j)\) 下方的石头的数量不超过 \((i,j)\) 下方的空格的数量的 \((k,j)\) ,可以看出来随着 \(k\) 不断往上途径的石头会越来越多,这个转折点是确实存在的。一个细节在于这个 \((k,j)\) 这行能不能通过向右走到 \((k,j)\) 是无关紧要的,反正也就加在一起,事实上 \((k,j)\) 应该是上边界某点或者正好在某块石头上(这块石头会被向右推走而不会被向下推,k再上升则会被向下推)

也就是 \(dp[i][j][1]=\sum\limits_{t=k}^{i-1}dp[t][j][0]\)

同理有 \(dp[i][j][0]=\sum\limits_{t=k}^{j-1}dp[i][t][1]\)

方程有了,边界怎么办? \((1,1)\) 格子既可以视作从左侧来也可以视作从上侧来,只是 \(n=m=1\) 的时候要特判掉。

怎么找k呢?以向下转移为例,很显然每个格子下方的石头数是递增的,可以保存每一行每一列的值直接二分,鉴于数据只有2000所以多个11倍常数问题不大。另一种方法是直接从上方的格子转移。

参考资料:

Technocup 2020 — Elimination Round 2 + Codeforces Round 596: analysis - Codeforces

CodeForces 1225E Rock Is Push(dp + 前缀和优化) - alpc_qleonardo - CSDN博客

Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2)的更多相关文章

  1. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) D. Power Products

    链接: https://codeforces.com/contest/1247/problem/D 题意: You are given n positive integers a1,-,an, and ...

  2. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) C. p-binary

    链接: https://codeforces.com/contest/1247/problem/C 题意: Vasya will fancy any number as long as it is a ...

  3. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) B2. TV Subscriptions (Hard Version)

    链接: https://codeforces.com/contest/1247/problem/B2 题意: The only difference between easy and hard ver ...

  4. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) A. Forgetting Things

    链接: https://codeforces.com/contest/1247/problem/A 题意: Kolya is very absent-minded. Today his math te ...

  5. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) F. Tree Factory 构造题

    F. Tree Factory Bytelandian Tree Factory produces trees for all kinds of industrial applications. Yo ...

  6. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) E. Rock Is Push dp

    E. Rock Is Push You are at the top left cell (1,1) of an n×m labyrinth. Your goal is to get to the b ...

  7. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) B. TV Subscriptions 尺取法

    B2. TV Subscriptions (Hard Version) The only difference between easy and hard versions is constraint ...

  8. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) A. Forgetting Things 水题

    A. Forgetting Things Kolya is very absent-minded. Today his math teacher asked him to solve a simple ...

  9. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) D. Power Products 数学 暴力

    D. Power Products You are given n positive integers a1,-,an, and an integer k≥2. Count the number of ...

随机推荐

  1. Oracle触发器编译错误及解决方案

    错误 TRIGGER **** 编译错误 错误:PLS-00103: 出现符号 "END"在需要下列之一时:        ( begin case declare exit    ...

  2. 利用WkHtmlToPdf,把H5 转成PDF

    工具下载地址: 链接:https://pan.baidu.com/s/1TSq2WWZcvPwuIfPRHST-FA 提取码:wkx8 原理: 通过IIS访问页面,利用WkHtmlToPdf.exe, ...

  3. 使用Django时需要注意的八个要点

    1.在settings.py中使用os. path.dirname() 常用代码如下: # settings.py import os PROJECT_DIR = os.path.dirname(__ ...

  4. 如何在windows server2016搭建DHCP服务器

    DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议.指的是由服务器控制一段IP地址范围,客户机登录服务器时就可以自动获得服务器分 ...

  5. mniGraffle常用快捷键

    OmniGraffle 是 Mac 上的绘图利器.Graffle 在很多方面对标 Windows 系统上的 Microsoft Visio,是制作各种文档的绝妙工具. 变换移动 放大:Cmd+Shif ...

  6. apache/tomcat笔记

    apache是什么? apache http server 简称apache是世界上排名前列的web服务器,因开源,简单,高性能,速度快,还可以做代理服务器,所以广受人们欢迎 httpd:httpd是 ...

  7. Java中ClassLoader浅析.

    一.问题 请在Eclipse中新建如下类,并运行它: 1 package java.lang; 2 3 public class Long { 4 public static void main(St ...

  8. AtCoder Grand Contest 032 B - Balanced Neighbors——构造

    题意 B - Balanced Neighbors 给定一个整数 $N$($3\leq N \leq 100$),构造一个顶点编号为 $1...N$ 的无向图,需满足如下两个条件: 简单图且连通 存在 ...

  9. 洛谷P1346 电车【最短路】

    题目:https://www.luogu.org/problemnew/show/P1346 题意:n个路口,每个路口有好几条轨道,默认指向给出的第一个路口. 如果要换到另外的轨道去需要按一次开关.问 ...

  10. fiddler修改请求和返回

    一.修改请求 1.先设置请求前断点 2.设置拦截,在左下角的QuickExec命令行中输入bpu www.baidu.com/XXXX 3.选中需要修改的请求,选中Inspectors面板,使用Raw ...