当前位置:   article > 正文

"字节跳动杯"2018中国大学生程序设计竞赛-女生专场(ing)_浙江省字节跳动杯

浙江省字节跳动杯

1002. 口算训练

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6287

Problem Description

小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为n的正整数序列a1,a2,...,an,要求小T抛出m个问题以训练他的口算能力。
每个问题给出三个正整数l,r,d,小Q需要通过口算快速判断al×al+1×...×ar−1×ar是不是d的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。

Input

第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。

每组数据第一行包含两个正整数n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。

第二行包含n个正整数a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。

接下来m行,每行三个正整数l,r,d(1≤l≤r≤n,1≤d≤100000),表示每个问题。

Output

对于每个问题输出一行,若是倍数,输出Yes,否则输出No。

 

Solution:

将输入的每个数分解质因数并记录,对d分解质因数并判断每个质因数在数组中是否有足够的因数。

[l, r] 中每个数相乘的结果是d的倍数,只需要 [l, r] 之间每个数的因数选择一些乘起来是 d 或 d 的倍数即可。但是暴力的储存查找会超时,所以可以通过用 vector 存因子 x 出现的所有坐标 i,然后再利用二分查找当前范围内由多少个因数。

注意,分解的时候要注意当前数是素数的情况。

 

Code:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cmath>
  5. #include <map>
  6. #include <cstdlib>
  7. #include <string>
  8. #include <iostream>
  9. #include <vector>
  10. #include <map>
  11. #include <queue>
  12. using namespace std;
  13. typedef long long LL;
  14. typedef pair<int, int> PII;
  15. const int MaxN = 1e5 + 5;
  16. vector<int> G[MaxN];
  17. int query(int l, int r, int x)
  18. {
  19. return upper_bound(G[x].begin(), G[x].end(), r) - lower_bound(G[x].begin(), G[x].end(), l);
  20. }
  21. bool check(int l, int r, int d)
  22. {
  23. for(int i = 2; i * i <= d; i++) {
  24. if(d % i == 0) { //对d分解质因数
  25. int cnt = 0;
  26. while(d % i == 0) {
  27. cnt++;
  28. d /= i;
  29. }
  30. if(query(l, r, i) < cnt) return 0;
  31. }
  32. }
  33. if(d > 1 && query(l, r, d) < 1) return 0; //如果当前数是素数
  34. return 1;
  35. }
  36. int main ()
  37. {
  38. int t; scanf("%d", &t);
  39. while(t--) {
  40. for(int i = 1; i <= MaxN; i++) G[i].clear();
  41. int n, m;
  42. scanf("%d %d", &n, &m);
  43. for(int i = 1; i <= n; i++) {
  44. int x; scanf("%d", &x);
  45. for(int j = 2; j * j <= x; j++) { //对数组中的数分解质因数
  46. while(x % j == 0) {
  47. x /= j;
  48. G[j].push_back(i); //对于每次当前的质因数都存储坐标i
  49. }
  50. }
  51. if(x > 1) G[x].push_back(i); //当前数是素数
  52. }
  53. while(m--) {
  54. int l, r, d;
  55. scanf("%d %d %d", &l, &r, &d);
  56. if(check(l, r, d)) printf("Yes\n");
  57. else printf("No\n");
  58. }
  59. }
  60. return 0;
  61. }

 

1003. 缺失的数据范围

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6288

Problem Description

著名出题人小Q出过非常多的题目,在这个漫长的过程中他发现,确定题目的数据范围是非常痛苦的一件事。
每当思考完一道题目的时间效率,小Q就需要结合时限以及评测机配置来设置合理的数据范围。
因为确定数据范围是一件痛苦的事,小Q出了非常多的题目之后,都没有它们设置数据范围。对于一道题目,小Q会告诉你他的算法的时间复杂度为O(nalogbn),且蕴含在这个大O记号下的常数为1。同时,小Q还会告诉你评测机在规定时限内可以执行k条指令。小Q认为只要na(⌈log2n⌉)b不超过k,那么就是合理的数据范围。其中,⌈x⌉表示最小的不小于x的正整数,即x上取整。
自然,小Q希望题目的数据范围n越大越好,他希望你写一个程序帮助他设置最大的数据范围。

 Input

第一行包含一个正整数T(1≤T≤1000),表示测试数据的组数。
每组数据包含一行三个正整数a,b,k(1≤a,b≤10,106≤k≤1018),分别描述时间复杂度以及允许的指令数。

 Output

对于每组数据,输出一行一个正整数n,即最大可能的n。

 

Description:

给出a、b、k,对于公式 na(log2n)bk 找出最大的n。

 

Range:

1 ≤ a, b ≤ 10

1e6 ≤ k ≤ 1e18

 

Solution:

二分查找可行解。

把公式分为 na 和 (log2n)b 两部分分别进行判断。

需要注意的两点是:

  • 乘法可能溢出,需要将乘法转换为除法 
  • 求 ⌈log2 n⌉ 时不能使用实数计算,会带来误差,应当使用整数计算。

 

Code:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <string>
  4. #include <cmath>
  5. #include <cstdlib>
  6. #include <ctime>
  7. #include <iostream>
  8. #include <algorithm>
  9. #include <vector>
  10. #include <queue>
  11. #include <stack>
  12. #include <set>
  13. #include <map>
  14. #define fi first
  15. #define se second
  16. #define mst(a, b) memset(a, b, sizeof(a))
  17. using namespace std;
  18. typedef long long LL;
  19. typedef pair<int, int> PII;
  20. const int INF = 0x3f3f3f3f;
  21. const double eps = 1e-9;
  22. const int Mod = 1e9 + 7;
  23. const int MaxN = 1e5 + 5;
  24. int a, b;
  25. LL k;
  26. LL log2(LL mid)
  27. {
  28. for(int i = 0; i <= 64; i++) {
  29. if(pow(2LL, i) >= mid) return i;
  30. }
  31. }
  32. bool check(LL mid)
  33. {
  34. LL pre = 1LL;
  35. for(int i = 1; i <= a; i++) { //判断前面部分
  36. if(pre <= k / mid) pre *= mid; //防止乘法溢出
  37. else return false; //当前的结果大于k说明不合法
  38. }
  39. LL base = log2(mid);
  40. LL suf = 1LL;
  41. if(suf == 0) return true; //否则会在下面的除法中出现RE
  42. for(int i = 1; i <= b; i++) { //判断后面部分
  43. if(suf <= k / mid) suf *= base;
  44. else return false;
  45. }
  46. if(pre <= k / suf) return true; //将两部分合起来判断一次
  47. return false;
  48. }
  49. int main()
  50. {
  51. //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
  52. int t; scanf("%d", &t);
  53. while(t--) {
  54. scanf("%d %d %lld", &a, &b, &k);
  55. LL l = 0LL, r = 1e18, ans = 0LL;
  56. while(l <= r) {
  57. LL mid = (l + r) / 2;
  58. if(check(mid)) l = mid + 1, ans = mid;
  59. else r = mid - 1;
  60. }
  61. cout << ans << endl;
  62. }
  63. return 0;
  64. }

 

1004. 寻宝游戏

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6289

Problem Description

小Q最近迷上了一款寻宝游戏,这款游戏中每局都会生成一个n×m的网格地图,从上往下依次编号为第1行到第n行,从左往右依次编号为第1列到第m列。每个格子上都有不同数量的金币,第i行第j列的格子上的金币数量为ai,j。
小Q一开始位于(1,1),每次他可以往右或者往下走,每当他经过某个格子时,他就可以拿走这个格子上的所有金币。小Q不能走出这个地图,当小Q不能再行动时,游戏结束。显然当且仅当小Q位于(n,m)时,游戏才会结束。
一轮游戏的得分为这一轮中收集到的金币总量,而在游戏开始前,因为小Q是超级VIP用户,所以他有k次机会交换某两个格子中的金币数。这k次机会不一定要用完,请写一个程序帮助小Q在一轮内拿到尽可能多的金币。

Input

第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含三个整数n,m,k(2≤n,m≤50,0≤k≤20),分别表示地图的长宽以及交换的次数。
接下来n行,每行m个整数ai,j(0≤ai,j≤106),依次表示每个格子中金币的数量。

 Output

对于每组数据,输出一行一个整数,即能收集到的金币数量的最大可能值。

 

Description:

对于 n*m 的矩阵每个点都有一个权值。从 (1, 1) 开始每次只能向下或向右走,求到达 (n, m) 时可以获得的最大值,其中你有k次交换机会交换任意两点上的权值。

 

Solution:

假设已经选定了一条路线,那么不考虑具体交换方案,考虑选定一个 t(t ≤ k),经过的格子里要有 t 个格子的权值不计入得分,而不经过的格子里要有 t 个格子的权值计入总分。那么每一种交换方案都可以对应这样一个转化。
设 fi,j,x,y  表示从 (1, 1)  出发来到 (i, j),考虑完前 i − 1 行所有格子以及第 i 行前 j 个格子时,有 x 个经过的格子不计分,y 个不经过的格子计分的情况下,总分的最大值是多少。那么有两种状态转移:

  • 往右走一格,直接转移到fi,j+1,x,y;
  • 往下走一格,转移到fi+1,j,x,y,需要枚举这一行有多少个不经过的格子计分。显然这些

格子一定按照权值从大到小贪心选择。
最终答案即为 max(fn,m,t,t) (0 ≤ t ≤ k)

时间复杂度O(n2k2)。

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/443292
推荐阅读
相关标签
  

闽ICP备14008679号