当前位置:   article > 正文

林大3.3训练 操作序列、角谷猜想、距离、矩阵线段、子数组【已更新完成】

林大3.3训练 操作序列、角谷猜想、距离、矩阵线段、子数组【已更新完成】

1、小蓝与操作序列(林大OJ 2347)

一道水题,先热热身

Description

小蓝学会了一种新的数据结构:栈。 
栈是一种仅在表尾进行插入和删除操作的线性表。 
表头被称为栈底,表尾被称为栈尾。
小蓝实现了一个支持四种操作的栈:
push:在栈顶压入一个元素, 
新元素会置于原本的栈顶上方,成为新的栈顶。
pop:弹出现在的栈顶,原本的栈顶将成为新的栈顶。 
如果此时栈中不存在元素,那么程序会出错。
top:返回现在的栈顶元素。 
如果此时栈中不存在元素,那么程序会出错。
clear:清空栈中元素,将栈置空。
但是他在使用这种数据结构时经常出错。 
现在他写出了自己使用栈时的一个操作序列, 
你能判断该操作序列是否合法吗? 
一个操作序列合法当且仅当 
一个空栈依次执行对应操作时不会出错。

Input

输入第一行包含一个整数N , 
代表操作序列的操作数目。

接下来包含 N 行,每行包含一个字符串,表示一个操作。 
该字符串一定是上述四个操作中的一个, 
即 "push" , "pop" , "top" 和 "clear" 
四种字符串中的一种(不包含引号)。

Output

输出两行。 
如果该操作序列合法,那么输出第一行 "Yes" ,第二行输出一个整数:最后栈中的元素数目; 
否则输出 "No" ,第二行输出一个整数:该操作序列会在执行第几个操作时出错(输出不包含引号)。

Sample Input

输入样例1
5
push
push
top
pop
push

Sample Output

输出样例1
Yes
2

Hint

输入样例 2
5
push
top
push
clear
pop
输出样例 2
No
5

代码:

这里用ele记录模拟栈中的元素个数,cnt来记录步骤数

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n;
  4. int main()
  5. {
  6. cin>>n;
  7. queue<string>q;
  8. for(int i=0;i<n;i++)
  9. {
  10. string op;
  11. cin>>op;
  12. q.push(op);
  13. }
  14. int cnt=0;
  15. int ele=0;
  16. bool f=true;
  17. while(!q.empty())
  18. {
  19. string s=q.front();
  20. q.pop();
  21. if(s=="push")
  22. {
  23. cnt++;
  24. ele++;
  25. }
  26. else if(s=="pop")
  27. {
  28. cnt++;
  29. if(ele==0)
  30. {
  31. f=false;
  32. break;
  33. }
  34. else
  35. {
  36. ele--;
  37. }
  38. }
  39. else if(s=="top")
  40. {
  41. cnt++;
  42. if(ele==0)
  43. {
  44. f=false;
  45. break;
  46. }
  47. }
  48. else
  49. {
  50. cnt++;
  51. ele=0;
  52. }
  53. }
  54. if(f)cout<<"Yes"<<endl<<ele;
  55. else cout<<"No"<<endl<<cnt;
  56. return 0;
  57. }

2、小兰与角谷猜想(林大OJ 2351)

Description

角谷猜想是指对于每一个正整数, 
如果它是奇数,则对它乘 3 再加1  , 
如果它是偶数,则对它除以2  , 
如此循环,最终都能够得到1 。

小蓝了解到,对于小于1000000000  的数字,我们总可以在 1000 步以内的得到 。 
现在他想知道, 【l,r】区间的数中哪个数得到 1 的步骤最大。

Input

输入包含一行,共两个整数 l 和r , 
表示小蓝想查询的区间。

Output

输出一行,包含一个整数, [l,r]区间的数中得到1  的步骤最大的那个数。 
如果存在多个步骤最大的数,那么输出最小的那个。

Sample Input

样例输入1
1 10

Sample Output

样例输出1
9

输入样例 2
999999900 1000000000
输出样例 2
999999906

Hint

这道题让我TLE了很长时间,以下是第一次的代码:TLE

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. unordered_map<LL,LL>m,re;
  5. LL odd(LL x)
  6. {
  7. x=x*3;
  8. x+=1;
  9. return x;
  10. }
  11. LL even(LL x)
  12. {
  13. x/=2;
  14. return x;
  15. }
  16. int main()
  17. {
  18. int l,r;
  19. cin>>l>>r;
  20. int big=0;
  21. int res;
  22. for(int i=l;i<=r;i++)
  23. {
  24. LL t=i;int cnt=0;
  25. while(t!=1)
  26. {
  27. if(re[t])
  28. {
  29. re[i]=cnt+re[t];
  30. cnt=re[i];
  31. break;
  32. }
  33. cnt++;
  34. if(m[t])t=m[t];
  35. else if(t%2==0)
  36. {
  37. m[t]=even(t);
  38. t=m[t];
  39. //cout<<t<<" ";
  40. }
  41. else
  42. {
  43. m[t]=odd(t);
  44. t=m[t];
  45. //cout<<t<<" ";
  46. }
  47. }
  48. re[i]=cnt;
  49. if(cnt>big)
  50. {
  51. //cout<<i<< " "<<cnt<<endl;
  52. big=cnt;
  53. res=i;
  54. }
  55. }
  56. cout<<res<<endl;//<<" "<<re[res];
  57. }

有一点并查集的感觉,但是两个表速度太慢了

实际上用深搜,加上记忆搜索,一个表就能解决

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. unordered_map <LL, LL> m;
  5. LL dfs(LL x)
  6. {
  7. if(m.count(x)) return m[x];
  8. if(x == 1) return 0;
  9. if(x & 1)
  10. return m[x] = 1 + dfs(3 * x + 1);
  11. else
  12. return m[x] = 1 + dfs(x / 2);
  13. }
  14. int main()
  15. {
  16. LL n, m;
  17. cin >> n >> m;
  18. LL maxn = 0, res = 0;
  19. for(int i = n; i <= m; ++ i)
  20. {
  21. LL ans = dfs(i);
  22. if(ans > maxn)
  23. {
  24. maxn = ans;
  25. res = i;
  26. }
  27. }
  28. cout << res << endl;
  29. return 0;
  30. }

3、小兰与名氏距离(林大OJ 2352)

Description

Input

输入第一行包含一个整数 N, 
表示二维空间中点的数目。

接下来包含 N 行,第行包含两个整数, 
表示一个点对的 X 坐标和 Y 坐标。

Output

输出一行,包含一个整数, 
表示距离与p  无关的点对数目。

Sample Input

3
0 1
1 0
1 1

Sample Output

2

Hint

**公式推导**:

这题就是求横坐标或者纵坐标相同的对数有多少个

对于相同的横纵坐标:这相当于一个对于n个重复元素,求不重复的组合数

比如:1 1 1 1 1

五个1,第一个1可以选后四个1:4

             第二个1可以选后三个1:3

             ...................

             最后一个1可以选0个

总共有4+3+2+1

可以转化为等差数列求和

求和公式 :(首项 + 末项) * 项数/2 

转化为这个之后,分别排序横坐标和纵坐标

用sum一直累加重复的对数就行了

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. const int N=1e5+10;
  5. int x[N],y[N];//存储x、y坐标
  6. int n;
  7. //相当于 n 个相同的数求前缀和
  8. // 1 1 1 1 2 相当于 三项 (i-stx-1)*(i-stx-1+1)就是这么来的
  9. // 3+2+1
  10. int main()
  11. {
  12. cin>>n;
  13. for(int i=0;i<n;i++)
  14. {
  15. scanf("%d%d",&x[i],&y[i]);
  16. }
  17. sort(x,x+n);
  18. sort(y,y+n);
  19. int stx=0,sty=0;
  20. LL sum=0;
  21. for(int i=1;i<n;i++)
  22. {
  23. if(x[stx]!=x[i])
  24. {
  25. sum+=(LL)(i-stx)*(i-stx-1)/2;//(首项 + 末项) * 项数/2
  26. stx=i;
  27. }
  28. if(y[sty]!=y[i])
  29. {
  30. sum+=(LL)(i-sty)*(i-sty-1)/2;
  31. sty=i;
  32. }
  33. }
  34. //最后可能到n-1的时候还没算完 比如说 9 9 9 9 一直到n-1最后一个
  35. //x【i】没有不等于 x【stx】
  36. //就算是 9 9 9 9 10形式的,用以下方式算也不会错
  37. //因为第n个不存在,到第n个也相当于一定不等于前面的,大不了sum+=0
  38. sum+=(LL)(n-stx)*(n-stx-1)/2;
  39. sum+=(LL)(n-sty)*(n-sty-1)/2;
  40. cout<<sum<<endl;
  41. return 0;
  42. }

4、小兰与线段(林大OJ 2353)

Description

给定一个仅包含 0和1,大小为N*M的矩阵。
小蓝想找到其中最长线段的长度。

Input

输入第一行包含两个整数 N 和M , 
表示矩阵的行和列数目。
接下来包含  N行,第i  行包含M  个整数, 
表示矩阵的第  i行。

Output

输出一行,包含一个整数,表示矩阵中最长线段的长度。

Sample Input

3 3
0 1 1
1 1 0
0 1 0

Sample Output

3

Hint

1<=N,M<=1000,数字仅包含0和1

代码:

选择两个方向进行深度优先搜索:dfsx()、dfsy()

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1005;
  4. int n,m;
  5. int t=max(n,m);
  6. int g[N][N];
  7. int vis[N][N],visx[N][N],visy[N][N];
  8. int dx[4]={1,-1};
  9. int dy[4]={1,-1};
  10. int dfsx(int x,int y)
  11. {
  12. int res=0;
  13. res+=1;
  14. //cout<<"+"<<endl;
  15. visx[x][y]=1;
  16. if(res==t)return res;
  17. for(int i=0;i<2;i++)
  18. {
  19. int nx=x+dx[i];
  20. if(!visx[nx][y] && nx>=1 && nx<=n && y>=1 && y<=m && g[x][y]==g[nx][y])
  21. {
  22. res+=dfsx(nx,y);//cout<<"yes"<<res<<endl;
  23. }
  24. }
  25. //cout<<"res=="<<res<<endl;
  26. return res;
  27. }
  28. int dfsy(int x,int y)
  29. {
  30. int res=0;
  31. res+=1;
  32. //cout<<"+"<<endl;
  33. visy[x][y]=1;
  34. if(res==t)return res;
  35. for(int i=0;i<2;i++)
  36. {
  37. int ny=y+dy[i];
  38. if(!visy[x][ny] && x>=1 && x<=n && ny>=1 && ny<=m && g[x][y]==g[x][ny])
  39. {
  40. res+=dfsy(x,ny);//cout<<"yes"<<res<<endl;
  41. }
  42. }
  43. //cout<<"res=="<<res<<endl;
  44. return res;
  45. }
  46. int main()
  47. {
  48. cin>>n>>m;
  49. for(int i=1;i<=n;i++)
  50. for(int j=1;j<=m;j++)
  51. {
  52. cin>>g[i][j];
  53. }
  54. int res=-1;
  55. for(int i=1;i<=n;i++)
  56. for(int j=1;j<=m;j++)
  57. {
  58. int t;
  59. if(!vis[i][j])
  60. {
  61. int x=dfsx(i,j);
  62. int y=dfsy(i,j);
  63. t=max(x,y);
  64. vis[i][j]=1;
  65. }
  66. //cout<<t<<endl;
  67. res=max(res,t);
  68. }
  69. cout<<res;
  70. return 0;
  71. }

5、小兰与子数组(林大OJ 2354)

Description

数组的范围是数组中最大元素和最小元素的差值。 
对于小蓝而言,求数组的范围是轻而易举的。 
但是现在,他想知道数组的所有子数组中, 
子数组范围的最大值和次大值。
子数组是由数组中的一个或连续多个整数组成一个数列

Input

输入包含两行。 
第一行包含一个整数N ,表示数组的长度。 
第一行包含 N 个整数,表示数组中各个元素的值。

Output

输出一行,包含两个整数,表示子数组范围的最大值和次大值。

Sample Input

5
4 3 2 1 4

Sample Output

3 3

Hint

代码:

用大顶堆、小顶堆维护最大值、次大值、最小值、次小值

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. priority_queue<int,vector<int>,greater<int>> qmin;
  4. priority_queue<int,vector<int>> qmax;
  5. int main()
  6. {
  7. int n;
  8. cin>>n;
  9. for(int i=0;i<n;i++)
  10. {
  11. int t;
  12. cin>>t;
  13. qmin.push(t);
  14. qmax.push(t);
  15. }
  16. long long ans[2];
  17. int cnt=0;
  18. int a,b,c,d;
  19. //最大减去最小
  20. int qma=qmax.top();qmax.pop();
  21. int qmi=qmin.top();qmin.pop();
  22. int qma1=qmax.top();
  23. int qmi1=qmin.top();
  24. a=qma-qmi;//最大减最小
  25. b=qma-qmi1;//最大减次小
  26. c=qma1-qmi;//次大减最小
  27. int t=max(b,c);
  28. cout<<a<<" "<<t;
  29. return 0;
  30. }

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

闽ICP备14008679号