当前位置:   article > 正文

2024年美团春招第一场笔试(技术)_小美拿到了一个 n n的矩阵,其中每个元素是 0 或者 1。 小美认

小美拿到了一个 n n的矩阵,其中每个元素是 0 或者 1。 小美认

1.

小美的平衡矩阵

小美拿到了一个n∗n的矩阵,其中每个元素是 0 或者 1。
小美认为一个矩形区域是完美的,当且仅当该区域内 0 的数量恰好等于 1 的数量。
现在,小美希望你回答有多少个i∗i的完美矩形区域。你需要回答1≤i≤n的所有答案。

解法:很明显,i若为奇数,则不可能是完美的。

对于偶数,枚举每个面积为 i*i的矩阵,判断一下这个矩阵的前缀和是不是面积的一半,是的话则符合题意,这题考察一个二维前缀和。

  1. #include<iostream>
  2. using namespace std;
  3. const int N = 210;
  4. int g[N][N], s[N][N];
  5. int n;
  6. int main() {
  7. cin >> n;
  8. for (int i = 1; i <= n; i++) {
  9. string str;
  10. cin >> str;
  11. int k = 0;
  12. for (int j = 1; j <= n; j++) {
  13. g[i][j] = str[k++] - '0';
  14. s[i][j] = g[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
  15. }
  16. }
  17. for (int i = 1; i <= n; i++) {
  18. if (i % 2) {
  19. cout << "0" << '\n';
  20. continue;
  21. }
  22. int res = 0;
  23. for (int j = i; j <= n; j++) {
  24. for (int k = i; k <= n; k++) {
  25. int sum = s[j][k] - s[j][k - i] - s[j - i][k] + s[j - i][k - i];
  26. if (sum == (i * i) / 2)res++;
  27. }
  28. }
  29. cout << res << '\n';
  30. }
  31. }

2.

2.

小美的数组询问

小美拿到了一个由正整数组成的数组,但其中有一些元素是未知的(用 0 来表示)。
现在小美想知道,如果那些未知的元素在区间[l,r]范围内随机取值的话,数组所有元素之和的最小值和最大值分别是多少?
共有q次询问。

解法:先把非0的数累加起来,然后接着想,怎样能让和最小和最大,很明显嘛,区间【L,R】是升序的,那么让那些未知数全部取L,自然加起来就是最小的,全部取R,自然就是最大的,纯纯送分题没啥好说的。

  1. #include<iostream>
  2. #define int long long
  3. using namespace std;
  4. int n,q;
  5. signed main()
  6. {
  7. cin>>n>>q;
  8. int sum = 0;
  9. int res = 0;
  10. for(int i = 1;i <= n; i++)
  11. {
  12. int x;
  13. cin>>x;
  14. if(x==0)res++;
  15. else sum +=x;
  16. }
  17. while(q--)
  18. {
  19. int l,r;
  20. cin>>l>>r;
  21. cout<<sum + res*l<<" "<<sum+res*r<<'\n';
  22. }
  23. return 0;
  24. }

3.

小美的 MT

MT 是美团的缩写,因此小美很喜欢这两个字母。
现在小美拿到了一个仅由大写字母组成字符串,她可以最多操作k次,每次可以修改任意一个字符。小美想知道,操作结束后最多共有多少个'M'和'T'字符?

解法:纯模拟题。遇到非M非T字符,只要还有操作次数,就直接变成M或者T就可以了,最后统计一下有多少个就可以了。

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int n,k;
  6. scanf("%d%d",&n,&k);
  7. int res = 0,ans=0;
  8. string str;
  9. cin>>str;
  10. for(int i = 0;i<str.size();i++)
  11. {
  12. if(str[i]=='T')res++;
  13. else if(str[i]=='M')res++;
  14. else ans++;
  15. }
  16. cout<<res + min(ans,k)<<'\n';
  17. return 0;
  18. }

4.小美的朋友关系

小美认为,在人际交往中,但是随着时间的流逝,朋友的关系也是会慢慢变淡的,最终朋友关系就淡忘了。
现在初始有一些朋友关系,存在一些事件会导致两个人淡忘了他们的朋友关系。小美想知道某一时刻中,某两人是否可以通过朋友介绍互相认识?
事件共有 2 种:
1 u v:代表编号 u 的人和编号 v 的人淡忘了他们的朋友关系。
2 u v:代表小美查询编号 u 的人和编号 v 的人是否能通过朋友介绍互相认识。

注:介绍可以有多层,比如 2 号把 1 号介绍给 3 号,然后 3 号再把 1 号介绍给 4 号,这样 1 号和 4 号就认识了。

解法:判断两个人是不是认识或者间接认识,很明显就是让我们判断在不在一个集合里面,顺着这个想法很快就想到并查集了,但是这个题目要删边(淡忘朋友关系),所以直接正向并查集不好做,并查集只能加边,所以这里要用反向并查集,逆序处理那些事件。

先把事件存起来,然后把是朋友关系的且没有被淡忘的关系并查集加边,然后从最后一个事件逆序往上做,这里要注意的一点::::要考虑重边!!!!!,比如添加{a,b}和{b,a},这应该是同一条边,要特别判断一下,然后反向处理的时候把答案也存起来,再把答案逆序打印出来就好了。

  1. #include<iostream>
  2. #include<vector>
  3. #include<unordered_map>
  4. #include<unordered_set>
  5. #include<set>
  6. using namespace std;
  7. typedef pair<int,int>PII;
  8. // 反向并查集
  9. set<pair<int,int>>hashs,all;
  10. unordered_map<int,int>p;
  11. unordered_set<int>person;
  12. int n,m,q;
  13. const int N=1000100;
  14. //int p[N];
  15. struct OP{
  16. int op, a,b;
  17. }Op[N];
  18. int find(int x)
  19. {
  20. if(p[x]!=x)p[x]=find(p[x]);
  21. return p[x];
  22. }
  23. int main()
  24. {
  25. // for(int i = 1;i<=n;i++)p[i]=i;
  26. cin>>n>>m>>q;
  27. for(int i = 1; i<=m;i++)
  28. {
  29. int a,b;
  30. cin>>a>>b;
  31. hashs.insert({a,b});
  32. all.insert({a,b});
  33. person.insert(a);
  34. person.insert(b);
  35. }
  36. // for(auto t : hashs)
  37. // {
  38. // cout<<t.first<<" "<<t.second<<endl;
  39. // }
  40. for(int i = 0; i < q;i++)
  41. {
  42. int op,a,b;
  43. cin>>op>>a>>b;
  44. Op[i]={op,a,b};
  45. person.insert(a);
  46. person.insert(b);
  47. if(op==1)
  48. {
  49. hashs.erase({a,b});
  50. hashs.erase({b,a});
  51. }
  52. }
  53. for(auto t : person)
  54. {
  55. p[t]=t;
  56. }
  57. for(auto pii:hashs)
  58. {
  59. int a= pii.first;
  60. int b= pii.second;
  61. p[find(a)]=find(b);
  62. }
  63. vector<string>ans;
  64. for(int i = q-1;i>=0;i--)
  65. {
  66. int op =Op[i].op;
  67. int a=Op[i].a;
  68. int b= Op[i].b;
  69. if(op==1){
  70. if(all.count({a,b})||all.count({b,a}))
  71. p[find(a)]=find(b);
  72. }
  73. else
  74. {
  75. if(find(a)==find(b))
  76. {
  77. ans.push_back("Yes");
  78. }
  79. else ans.push_back("No");
  80. }
  81. }
  82. for(int i = ans.size()-1;i>=0;i--)
  83. cout<<ans[i]<<'\n';
  84. return 0;
  85. }

5.

小美的区间删除

小美拿到了一个大小为n的数组,她希望删除一个区间后,使得剩余所有元素的乘积末尾至少有k个 0。小美想知道,一共有多少种不同的删除方案?

解法:乘积末尾至少要有k个0,那么剩余区间里的数2的因子和5的因子均不能少于k个,

可以先把每个数2的因子和5的因子统计出来,并且累加到c2和c5上
接着采用双指针做法,L指针固定左端点,R指针固定右端点,[L,R]这段区间表示要删除的区间

R指针每右移一位,若当前剩余的因子数仍满足k个,那么就会增加R - L +1个可行删除区间(会影响前R-L个数,并且多了当前新增的这个数,所以是R-L+1),若不满足了,说明左指针需要移动了。

  1. #include<iostream>
  2. #include<unordered_map>
  3. #include<cmath>
  4. using namespace std;
  5. typedef long long LL;
  6. const int N = 1000010;
  7. int n,k;
  8. int s[N];
  9. LL sum;
  10. LL c2,c5;
  11. LL cnt2[N],cnt5[N];
  12. int getNums(int x,int num)
  13. {
  14. int res=0;
  15. while(x%num==0)
  16. {
  17. x/=num;
  18. res++;
  19. }
  20. return res;
  21. }
  22. int main()
  23. {
  24. cin>>n>>k;
  25. for(int i = 1;i<=n;i++)
  26. {
  27. int x;
  28. cin>>x;
  29. cnt2[i] = getNums(x,2);
  30. cnt5[i] = getNums(x,5);
  31. c2+=cnt2[i];
  32. c5+=cnt5[i];
  33. // cout<<cnt2[i]<<" "<<cnt5[i]<<'\n';
  34. }
  35. // cout<<c2<<" "<<c5<<'\n';
  36. LL res=0;
  37. for(int l = 1, r= 1; r<=n;r++)
  38. {
  39. c2-=cnt2[r];
  40. c5-=cnt5[r];
  41. while(min(c2,c5)<k&&l<=n)
  42. {
  43. c2+=cnt2[l];
  44. c5+=cnt5[l];
  45. l++;
  46. }
  47. if(r>=l)
  48. res +=r-l+1;
  49. }
  50. printf("%lld",res);
  51. }

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

闽ICP备14008679号