当前位置:   article > 正文

刷题记录(自己看的习题本)_第五届山东师范大学与齐鲁工业大学icpc新生联谊赛题解

第五届山东师范大学与齐鲁工业大学icpc新生联谊赛题解

区间和(离散化)

题目链接:802. 区间和 - AcWing题库

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;
  5. const int N = 300010; //n次插入和m次查询相关数据量的上界
  6. int n, m;
  7. int a[N];//存储坐标插入的值
  8. int s[N];//存储数组a的前缀和
  9. vector<int> alls; //存储(所有与插入和查询有关的)坐标
  10. vector<pair<int, int>> add, query; //存储插入和询问操作的数据
  11. int find(int x) { //返回的是输入的坐标的离散化下标
  12. int l = 0, r = alls.size() - 1;
  13. while (l < r) {
  14. int mid = l + r >> 1;
  15. if (alls[mid] >= x) r = mid;
  16. else l = mid + 1;
  17. }
  18. return r + 1;
  19. }
  20. int main() {
  21. scanf("%d%d", &n, &m);
  22. for (int i = 1; i <= n; i++) {
  23. int x, c;
  24. scanf("%d%d", &x, &c);
  25. add.push_back({x, c});
  26. alls.push_back(x);
  27. }
  28. for (int i = 1; i <= m; i++) {
  29. int l , r;
  30. scanf("%d%d", &l, &r);
  31. query.push_back({l, r});
  32. alls.push_back(l);
  33. alls.push_back(r);
  34. }
  35. //排序,去重
  36. sort(alls.begin(), alls.end());
  37. alls.erase(unique(alls.begin(), alls.end()), alls.end());
  38. //执行前n次插入操作
  39. for (auto item : add) {
  40. int x = find(item.first);
  41. a[x] += item.second;
  42. }
  43. //前缀和
  44. for (int i = 1; i <= alls.size(); i++) s[i] = s[i-1] + a[i];
  45. //处理后m次询问操作
  46. for (auto item : query) {
  47. int l = find(item.first);
  48. int r = find(item.second);
  49. printf("%d\n", s[r] - s[l-1]);
  50. }
  51. return 0;
  52. }
  53. /*作者:liangshang
  54. 链接:https://www.acwing.com/solution/content/13511/
  55. 来源:AcWing
  56. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*/

区间合并(区间合并)

题目链接:803. 区间合并 - AcWing题库

问题:给出多个区间,合并有交集的区间,最后得出剩余的单独区间有多少个。

思路:

 用维护左右端点的数据typedef pair<int, int> PII; typedef pair<int, int> PII;

 区间之间分为3种情况:完全没有交集,完全合并为一个大区间,有交集。

对vector<PII> segs排序

维护一个区间,每次这个区间对比下一个区间的3种情况。没有交集就存入vector<PII> res;

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef pair<int, int> PII;
  6. void merge(vector<PII> &segs) //模版
  7. {
  8. vector<PII> res;
  9. sort(segs.begin(), segs.end());
  10. int st = -2e9, ed = -2e9;
  11. for (auto seg : segs)
  12. if (ed < seg.first)
  13. {
  14. if (st != -2e9) res.push_back({st, ed});
  15. st = seg.first, ed = seg.second;
  16. }
  17. else ed = max(ed, seg.second);
  18. if (st != -2e9) res.push_back({st, ed});
  19. segs = res;
  20. }
  21. int main()
  22. {
  23. int n;
  24. scanf("%d", &n);
  25. vector<PII> segs;
  26. for (int i = 0; i < n; i ++ )
  27. {
  28. int l, r;
  29. scanf("%d%d", &l, &r);
  30. segs.push_back({l, r});
  31. }
  32. merge(segs);
  33. cout << segs.size() << endl;
  34. return 0;
  35. }

数学

 2582. 递枕头(模拟)(数学)

问题描述:

n 个人站成一排,按从 1 到 n 编号。

最初,排在队首的第一个人拿着一个枕头。每秒钟,拿着枕头的人会将枕头传递给队伍中的下一个人。一旦枕头到达队首或队尾,传递方向就会改变,队伍会继续沿相反方向传递枕头。

  • 例如,当枕头到达第 n 个人时,TA 会将枕头传递给第 n - 1 个人,然后传递给第 n - 2 个人,依此类推。

给你两个正整数 n 和 time ,返回 time 秒后拿着枕头的人的编号。

思路:暴力模拟或者数学找规律

  1. class Solution {
  2. public:
  3. int passThePillow(int n, int time) {
  4. /*找规律*/
  5. time %= (n - 1) * 2;
  6. return time < n ? time + 1 : n * 2 - time - 1;
  7. }
  8. };
  9. /*
  10. 模拟:
  11. int ans = 1, k = 1;
  12. while (time--) {
  13. ans += k;
  14. if (ans == 1 || ans == n) {
  15. k *= -1;
  16. }
  17. }
  18. return ans;
  19. */

 AcWing 868. 筛质数(数学)(筛质数) 

问题描述:给一个数n,筛出1到n里所有的质数的个数 

思路与理解:

1.朴素:从2开始,筛出每个2的倍数,比如4,6,8,10.再从3开始筛出每个3的倍数,6,9,12,

代码:

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. const int N= 1000010;
  5. int primes[N], cnt;
  6. bool st[N];
  7. void get_primes(int n)
  8. {
  9. for (int i = 2; i <= n; i ++ )
  10. {
  11. if (st[i]) continue;
  12. primes[cnt ++ ] = i;
  13. for (int j = i + i; j <= n; j += i)
  14. st[j] = true;
  15. }
  16. }
  17. int main()
  18. {
  19. int n;
  20. cin >> n;
  21. get_primes(n);
  22. cout << cnt << endl;
  23. return 0;
  24. }

蛇形填数(数学)

题目链接:蛇形填数 - 蓝桥云课 (lanqiao.cn)

题解:(蓝桥杯填空题原题)这个题就是个找规律题。根据题目提示找到数与数之间的规律。

faa70f7fb9c44db99654b5df0fcce5db.png

2020年第十一届蓝桥杯 - 省赛 - C/C++大学生A组 - C.蛇形填数_哔哩哔哩_bilibili

代码:

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int n=20,ans=1;
  6. for (int i=0;i<n;i++)
  7. {
  8. ans+=i*4;
  9. }
  10. cout <<ans<<endl;
  11. return 0;
  12. }

P2241 统计方形(数学)

描述:给一个n * m 的矩形,得出这个矩形里面有多少个正方形和长方形

代码:

  1. #include<iostream>
  2. using namespace std;
  3. long long n,m,rec,sqr;
  4. int main() {
  5. cin>>n>>m;
  6. for(int i=0; i<n; i++)//循环,从n-0到n-(n-1)
  7. for(int j=0; j<m; j++) {//循环,从m-0到m-(m-1)
  8. if(i==j) sqr+=(n-i)*(m-j);//如果i==j,说明是正方形
  9. else rec+=(n-i)*(m-j);//如果不等说明是矩形
  10. }
  11. cout<<sqr<<" "<<rec<<endl;//输出
  12. return 0;
  13. }

详细理解见:P2241 统计方形(数据加强版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

此类数学题 遇到了就会,没遇到就不会。当公式记住了

                if(i==j) sqr+=(n-i)*(m-j);//如果i==j,说明是正方形
                    else rec+=(n-i)*(m-j);//如果不等说明是矩形

bhq的小物块(数学)

链接:L-bhq的小物块_第五届山东师范大学与齐鲁工业大学ICPC新生联谊赛 (nowcoder.com)

描述:b2ea60c61fef4c5aa467e3afcd923c47.png

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long int64;
  4. const double PI = M_PI;
  5. void solve(){
  6. int n;
  7. cin >> n;
  8. cout << (int64)(PI * pow(10L, n)) << endl;
  9. }
  10. int main(){
  11. int t;
  12. cin >> t;
  13. while(t-- > 0) solve();
  14. }

学习了:

1.pow(10L, n)

表示10的n次方,10L 的 L 表示这个10是 long 型的

2.库里面的pi值 const double PI = M_PI;

P1143 进制转换

链接:P1143 进制转换 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

描述:

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. string a;
  4. int c[10000000],d,e,f,g,sum,ans;
  5. int main()
  6. {
  7. scanf("%d",&d);
  8. cin>>a;
  9. scanf("%d",&f);
  10. /*for(int x=0;x<a.size();x++){
  11. if(a[x]<'A'){
  12. e=pow(d,a.size()-x-1);
  13. e*=(a[x]-'0');
  14. sum+=e;
  15. }
  16. else{
  17. e=pow(d,a.size()-1-x);
  18. e*=(a[x]-'A'+10);
  19. sum+=e;
  20. }
  21. }手写方法转换成10进制*/
  22. sum=stoi(a,NULL,d); //d进制转换成10进制
  23. while(sum>0){
  24. c[g++]=sum%f;
  25. sum/=f; //sum(10进制)转换成f进制
  26. }
  27. for(int x=g-1;x>=0;x--){
  28. if(c[x]>=10)printf("%c",c[x]+'A'-10);
  29. else printf("%d",c[x]);
  30. }
  31. return 0;
  32. }

 学习的都在代码里面了:

1. sum=stoi(a,NULL,d); //d进制转换成10进制

2.

//sum(10进制)转换成f进制

 while(sum>0){
        c[g++]=sum%f;
        sum/=f;   
    }
    for(int x=g-1;x>=0;x--){
        if(c[x]>=10)printf("%c",c[x]+'A'-10);
        else printf("%d",c[x]);
    }

885. 求组合数 I(排列组合)

链接:885. 求组合数 I - AcWing题库

描述:

代码(直接开背):

  1. #include<iostream>
  2. using namespace std;
  3. const int mod = 1e9+7;
  4. long long f[2010][2010];
  5. int main()
  6. {
  7. //预处理
  8. for(int i=0;i<=2000;i++)
  9. {
  10. for(int j=0;j<=i;j++)
  11. {
  12. if(!j) f[i][j]=1;
  13. else f[i][j]=(f[i-1][j-1]+f[i-1][j])%mod;
  14. }
  15. }
  16. int n;
  17. cin>>n;
  18. while(n--)
  19. {
  20. int a,b;
  21. cin>>a>>b;
  22. printf("%ld\n",f[a][b]);
  23. }
  24. }

AcWing 1205. 买不到的数目(数论)(结论题)

链接:1205. 买不到的数目 - AcWing题库

描述:

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int main ()
  4. {
  5. cin.tie(0);
  6. cout.tie(0);
  7. ios::sync_with_stdio(false);
  8. int a,b;
  9. cin >>a>>b;
  10. cout <<(a-1)*(b-1)-1<<endl;
  11. return 0;
  12. }

数学结论:如果两个数互质a,b(公约数只有1的两个数叫做互质数。 根据互质数的概念可以对一组数是否互质进行判断。 如:9和11的公约数只有1,则它们是互质数。)则不能凑出来的最大整数是(a-1)*(b-1)-1

1211. 蚂蚁感冒

链接:1211. 蚂蚁感冒 - AcWing题库

描述: 

 悟:

数学方面 建立好图(画好图)有利于更好的解决问题,然后是学会等价代还思维。就是根据描述等价成一个更易理解和利用的有效条件

1216. 饮料换购

链接:AcWing 1216. 饮料换购 - AcWing

描述:

代码1:直觉的做法

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int n;
  6. cin >> n;
  7. int res = n;
  8. while (n >= 3)
  9. {
  10. res += n / 3;
  11. n = n / 3 + n % 3;
  12. }
  13. cout << res << endl;
  14. return 0;
  15. }

自己的做法就是这个,可是自己的代码太辣鸡了,忘了%可以直接得到除法之后的余数

代码2:等价代还出结论,换一瓶饮料,少俩盖

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. using namespace std;
  5. int main()
  6. {
  7. int n;
  8. cin>>n;
  9. int res=n;
  10. while(n>=3)
  11. {
  12. n-=2; //换一瓶饮料,少俩盖
  13. res++;
  14. }
  15. cout<<res;
  16. }

代码3:直觉做法+dfs(练习dfs大法的写法与用法)

  1. #include <iostream>
  2. using namespace std;
  3. int cnt;
  4. int dfs(int u){
  5. if(u<3) return cnt;
  6. dfs(u-2);
  7. cnt++;
  8. }
  9. int main(){
  10. int n;
  11. cin>>n;
  12. cout<<dfs(n)+n;
  13. return 0;
  14. }
  1. #include <iostream>
  2. using namespace std;
  3. int cnt;
  4. int dfs(int u){
  5. if(u<3) return cnt;
  6. dfs(u/3+u%3);
  7. cnt+=u/3;
  8. }
  9. int main(){
  10. int n;
  11. cin>>n;
  12. cout<<dfs(n)+n;
  13. return 0;
  14. }

4956. 冶炼金属(数学)(推公式)

链接:4956. 冶炼金属 - AcWing题库

描述 : 

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main ()
  4. {
  5. int n;
  6. cin >>n;
  7. int mi=0,mx=1e9;
  8. for (int i=1;i<=n;i++)
  9. {
  10. int a,b;
  11. cin >>a>>b;
  12. int r= a/b, l =a/(b+1) +1;
  13. mi = max (mi,l),mx= min (mx,r);
  14. }
  15. cout <<mi <<' '<<mx <<endl;
  16. return 0;
  17. }

 

细节: 最小值没有取到等于 所以算出的数要加上1,要是取到等于就不用 ,这样就都在那个范围内了(这就是数学转换到计算机编程计算时候的细节注意) 

基础算法

史蒂夫的农场(模拟)

题目链接:D-史蒂夫的农场_一石月赛(第八期) (nowcoder.com)

问题描述:1fbc556495ac4ca7a166d02727e28336.png

补:注意题目的意思是没有必须左右相邻的树判断高度,所以例如1 0 0 0 0 0 1的结果 应是5

代码:

  1. #include<iostream>
  2. using namespace std;
  3. const int N=1e5+10;
  4. int nums[N];
  5. int main() {
  6. ios::sync_with_stdio(false);
  7. cin.tie(0);
  8. cout.tie(0);
  9. int n;
  10. cin >> n;
  11. //int* nums = new int [n];
  12. int mai = 0;
  13. for (int i = 0; i < n; i++) {
  14. cin >> nums[i];
  15. if (nums[i] > nums[mai])
  16. mai = i;
  17. }
  18. long long sum = 0;
  19. for (int i = 0, si = i; i < mai; i++) {
  20. if (nums[i] > nums[si])
  21. si = i;
  22. else sum += nums[si] - nums[i];
  23. }
  24. for (int i = n - 1, si = i; i > mai; i--) {
  25. if (nums[i] > nums[si])
  26. si = i;
  27. else sum += nums[si] - nums[i];
  28. }
  29. cout << sum;
  30. }

做题感想:

关于需要模拟的题就是阅读理解,要是理解错误,还不如一开始就不写,从一开始出发的方向都是错的。

怀疑自己是毒药。永远不要怀疑自己。不要给自己怀疑自己的机会。我信奉条理,只要按照一定的条理就会接近目的,达成目的。自己按照条理,就没有什么是自己的问题。

这题做不出来我还差点怀疑自己最近脑子玩坏了,结果其实就是题的问题。不是我的问题。

P1042  乒乓球(模拟)

链接:P1042 [NOIP2003 普及组] 乒乓球 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

描述:

代码:

  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. int win[62503];
  5. int w,l;
  6. int main()
  7. {
  8. char s;
  9. for(int i=1;cin>>s&&s!='E';i++)//循环读入,当读到字符E结束
  10. {
  11. if(s=='W')win[i]=1;
  12. else win[i]=2;
  13. }
  14. //----------------11分制 ----------------
  15. for(int i=1;1;i++)
  16. {
  17. if(win[i]==1)w++;//胜场+1
  18. if(win[i]==2)l++;//负场+1
  19. if(win[i]==0)//读到0则记录结束,输出记录结束前的分数。
  20. {
  21. cout<<w<<":"<<l<<endl<<endl;
  22. break;
  23. }
  24. if(w-l>=2||l-w>=2)
  25. if(w>=11||l>=11)//当双方比分相差大于2且一方分数大等于11输出
  26. {
  27. cout<<w<<":"<<l<<endl;
  28. w=0;//比分清零
  29. l=0;
  30. }
  31. }
  32. w=0;//清零,为21分制计算做准备
  33. l=0;
  34. //----------------21分制 ----------------
  35. for(int i=1;1;i++)//一切同上,唯一区别就是判定从11变为21
  36. {
  37. if(win[i]==1)w++;
  38. if(win[i]==2)l++;
  39. if(win[i]==0)
  40. {
  41. cout<<w<<":"<<l;
  42. break;
  43. }
  44. if(w-l>=2||l-w>=2)
  45. if(w>=21||l>=21)//11变为21
  46. {
  47. cout<<w<<":"<<l<<endl;
  48. w=0;
  49. l=0;
  50. }
  51. }
  52. return 0;//华丽地结束 ㄟ(▔▽▔)ㄏ
  53. }

榫卯结构(模拟)

链接:B-榫卯结构_重庆移通学院第七届大学生程序设计大赛 (nowcoder.com)

描述:

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main()
  4. {
  5. int n; cin >> n;
  6. string s[n][3];
  7. for (int i = 0; i < 3; i++) {
  8. for (int j = 0; j < n; j++) {
  9. cin >> s[j][i];
  10. }
  11. }
  12. int a[8]; memset(a, 0, sizeof(a));
  13. for (int i = 0; i < n; i++) {
  14. // 第一对
  15. if (s[i][0] == ".#.") a[0]++;
  16. if (s[i][2] == "#.#") a[4]++;
  17. // 第二对
  18. if (s[i][0][2] == '.' && s[i][2][2] == '.') a[1]++;
  19. if (s[i][1][0] == '.') a[5]++;
  20. // 第三对
  21. if (s[i][2] == ".#.") a[2]++;
  22. if (s[i][0] == "#.#") a[6]++;
  23. // 第四对
  24. if (s[i][0][0] == '.' && s[i][2][0] == '.') a[3]++;
  25. if (s[i][1][2] == '.') a[7]++;
  26. }
  27. if (a[0] == a[4] && a[1] == a[5] && a[2] == a[6] && a[3] == a[7]) {
  28. cout << "Yes";
  29. } else {
  30. cout << "No";
  31. }
  32. return 0;
  33. }

这个题就是被卡输入了我当时比赛的时候。我的思路是没有问题的。
输入应该这样理解:只输入三行,一行有n个小字符串。(n就是总共有多少个部件)

然后这个代码我学习了还可以这样定义string数组 string s[n][3]; 这样就是一个数组内的类型就是一个字符串。然后还可以开的是二维,最后再用三维表示某个点的具体位置
比如这个s[i][0][2] == '.'  意思就是 第i个字符串的第1行(0+1)的第3(2+1)个此处的字符(注意是字符)是‘.’
后面的三维s都是这样理解。

也有教训:好好读题。尤其是疑惑的时候,再多认真读读题,一是冷静下来,二是看遗漏了什么

P267 扫雷游戏(模拟)

链接:P2670 [NOIP2015 普及组] 扫雷游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

描述:

代码:

  1. #include<iostream>
  2. using namespace std;
  3. char a[105][105];
  4. int b[105][105],n,m,i,j;//数组定义(二维)
  5. int main()
  6. {
  7. cin>>n>>m;//读入行、列
  8. for(i=1;i<=n;i++)
  9. for(j=1;j<=m;j++)
  10. {
  11. cin>>a[i][j];
  12. if(a[i][j]=='*')//判断:如果是地雷
  13. {
  14. b[i+1][j+1]++;
  15. b[i+1][j-1]++;
  16. b[i+1][j]++;
  17. b[i][j+1]++;
  18. b[i][j-1]++;
  19. b[i-1][j]++;
  20. b[i-1][j+1]++;
  21. b[i-1][j-1]++;//相邻的八个格子都+1
  22. }
  23. }
  24. for(i=1;i<=n;i++)
  25. {
  26. for(j=1;j<=m;j++)
  27. {
  28. if(a[i][j]=='*')
  29. cout<<"*";//如果是地雷(*) 原样输出
  30. else
  31. cout<<b[i][j];//否则输出数字
  32. }
  33. cout<<endl;
  34. }
  35. return 0;
  36. }

这题居然神奇的不用防止数组越界。可能是+1-1 本来就比较小,而且是从i==1,j==1开始遍历的。

1245. 特别数的和(模拟)

链接:1245. 特别数的和 - AcWing题库

描述:

代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. int main()
  5. {
  6. int n;
  7. cin >> n;
  8. int res = 0;
  9. for (int i = 1; i <= n; i ++ )
  10. {
  11. int x = i;
  12. while(x)
  13. {
  14. int t = x % 10; // 取出x的个位数
  15. x /= 10; // 取它的上一位
  16. if (t == 0 || t == 2 || t == 1 || t == 9)
  17. {
  18. res += i;
  19. break;
  20. }
  21. }
  22. }
  23. cout << res << endl;
  24. return 0;
  25. }

AcWing 466. 回文日期(模拟)

链接:466. 回文日期 - AcWing题库

描述: 

思路 : 

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. int months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  7. bool check(int date)
  8. {
  9. int year = date / 10000;
  10. int month = date % 10000 / 100;
  11. int day = date % 100;
  12. if (!month || month >= 13 || !day) return false;
  13. if (month != 2 && day > months[month]) return false;
  14. if (month == 2)
  15. {
  16. bool leap = year % 4 == 0 && year % 100 || year % 400 == 0;
  17. //判断闰年公式
  18. if (day > 28 + leap) return false;
  19. }
  20. return true;
  21. }
  22. int main()
  23. {
  24. int date1, date2;
  25. cin >> date1 >> date2;
  26. int res = 0;
  27. for (int i = 0; i < 10000; i ++ )
  28. {
  29. int x = i, r = i;
  30. for (int j = 0; j < 4; j ++ ) r = r * 10 + x % 10, x /= 10;
  31. //根据前面4位数造后四位回文
  32. if (r >= date1 && r <= date2 && check(r)) res ++ ;
  33. }
  34. printf("%d\n", res);
  35. return 0;
  36. }

AcWing 1204. 错误票据(模拟)(哈希计数)

链接:AcWing 1204. 错误票据 - AcWing

描述:

思路:

本题关键在于输入,思路很好想就是用哈希计数然后找出特定的只出现2次和0次的数就行

Oj输入钻漏子输入法:

cin >> n;//这个读入没什么用

    int minv = INF, maxv = -INF;

    int tp;

    while(cin >> tp)//直接读到文件尾部停止

    {

        if(tp < minv)   minv = tp;

        if(tp > maxv)   maxv = tp;

        ha[tp] ++;

}

正规c++语法处理整行输入的一组数:

string line;

    getline(cin, line); // 忽略掉第一行的回车

    while (cnt -- )

    {

        getline(cin, line);

        stringstream ssin(line);

        while (ssin >> a[n]) n ++ ;

    }

一整行带空格字母:

string str="i am a boy"; 

    istringstream is(str); 

    string s; 

    while(is>>s)  { 

        cout<<s<<endl; 

    } 

代码:

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. const int N = 1e5+5, INF = 0x3f3f3f3f;
  5. int ha[N];
  6. int main()
  7. {
  8. int n;
  9. cin >> n;//这个读入没什么用
  10. int minv = INF, maxv = -INF;
  11. int tp;
  12. while(cin >> tp)//直接读到文件尾部停止
  13. {
  14. if(tp < minv) minv = tp;
  15. if(tp > maxv) maxv = tp;
  16. ha[tp] ++;
  17. }
  18. int ans1 = 0, ans2 = 0;
  19. for(int i = minv; i <= maxv; ++ i)
  20. {
  21. if(ha[i] == 0) ans1 = i;
  22. if(ha[i] == 2) ans2 = i;
  23. }
  24. cout << ans1 << " " << ans2 << endl;
  25. }

P3613 寄包柜(模拟)(优化)(map_STL)

链接:P3613 【深基15.例2】寄包柜 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

描述:

 代码:

  1. #include<cstdio>
  2. #include<map>
  3. using namespace std;
  4. int n,q,p,k;
  5. map<long long,int>b;
  6. long long i,j;
  7. int main()
  8. {
  9. scanf("%d%d",&n,&q);
  10. while(q--)
  11. {
  12. scanf("%d%d%d",&p,&i,&j);
  13. if(p==1)
  14. {
  15. scanf("%d",&k);
  16. b[i*100000+j]=k;
  17. }
  18. else printf("%d\n",b[i*100000+j]);
  19. }
  20. return 0;
  21. }

学习了:

开long long int a[5000][5000]会爆掉(二维数组的上限1e5)

这里使用map<long long,int>b;

 136. 只出现一次的数字(位运算)

问题描述:给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

思路与理解:要对位运算有一个高度的理解,不然还是用哈希表和其他方式解决好理解一些。

 c272e5beb00e425e8d2efd85deb5d3c6.png

  1. class Solution {
  2. public:
  3. int singleNumber(vector<int>& nums) {
  4. int res = 0;
  5. for(int num : nums) res ^= num;
  6. return res;
  7. }
  8. };

注意:这个方法只能处理2个相同的数。处理3个相同的数,找出2个个数为1的数又要另外写代码了。

1024节快乐!(位运算)

问题描述:给你一个16进制数,转换成10进制,然后对1024取模

代码:

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. long long int f(string m)
  5. {
  6. long long int res=0,x=0;
  7. int size=m.size();
  8. for(int i = size - 1; res <= 1024 && i >= 0; i--)
  9. {
  10. //模1024 这里必须写res <= 1024 && i >= 0
  11. //当 dec 大于 1024时 直接 % 1024 即可
  12. //<< 4 等价于 * 16
  13. if(m[i]>='0'&&m[i]<='9'){
  14. res = res + ((m[i] - '0') << x);
  15. }else if(m[i]>='A'&&m[i]<='Z'){
  16. res = res + ((m[i] - 'A' + 10) << x);
  17. }else{
  18. res = res + ((m[i] - 'a' + 10) << x);
  19. }
  20. x += 4;
  21. }
  22. return res%1024;
  23. }
  24. int main ()
  25. {
  26. string n;
  27. cin >>n;
  28. cout<<f(n)<<endl;
  29. return 0;
  30. }

P1469 找筷子(位运算)

链接:P1469 找筷子 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

描述: 

理解:其实和136.只出现一次的数一个原理

代码(自己写的): 

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e7+5;
  4. int main ()
  5. {
  6. cin.tie(0);
  7. cout.tie(0);
  8. ios::sync_with_stdio(false);
  9. long long int n,a,res=0;
  10. cin >>n;
  11. for (int i=0;i<n;i++)
  12. {
  13. cin >>a;
  14. res^=a;
  15. }
  16. cout <<res<<endl;
  17. return 0;
  18. }

P1100 高低位交换(位运算)

链接:P1100 高低位交换 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

描述:

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int main(){
  4. unsigned int n;
  5. cin>>n;
  6. cout<<(n>>16)+(n<<16);
  7. return 0;
  8. }

学习了:

 789. 数的范围(二分)

题目链接:789. 数的范围 - AcWing题库

问题描述:77032cb3bb5b4ecab9c463e5865b5e49.png

题解:这里需要二分出数的始末位置,所以要写两个二分来找到始位置和末位置。

找开始的位置二分写法和找末尾的位置的写法不同。需要注意

代码:

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100010;
  4. int n, m;
  5. int q[N];
  6. int main()
  7. {
  8. scanf("%d%d", &n, &m);
  9. for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
  10. while (m -- )
  11. {
  12. int x;
  13. scanf("%d", &x);
  14. int l = 0, r = n - 1;
  15. while (l < r) //找到最后l==r ,跳出循环
  16. {
  17. int mid = l + r >> 1;
  18. if (q[mid] >= x) r = mid; //找始位置
  19. else l = mid + 1;
  20. }
  21. if (q[l] != x) cout << "-1 -1" << endl;
  22. else
  23. {
  24. cout << l << ' ';
  25. int l = 0, r = n - 1;
  26. while (l < r)
  27. {
  28. int mid = l + r + 1 >> 1;
  29. if (q[mid] <= x) l = mid; //找末位置
  30. else r = mid - 1;
  31. }
  32. cout << l << endl;
  33. }
  34. }
  35. return 0;
  36. }

790. 数的三次方根(二分)

链接:790. 数的三次方根 - AcWing题库

描述: 

代码:

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. int main()
  5. {
  6. double a;
  7. cin >>a;
  8. if (a>0)
  9. {
  10. double l=0,r=a;
  11. while (r-l>1e-8)
  12. {
  13. double x=(l+r)/2;
  14. if (x*x*x>=a) r=x;
  15. else l=x;
  16. }
  17. printf("%.6lf\n", l);
  18. }
  19. else if (a<0)
  20. {
  21. double l=a,r=0;
  22. while (r-l>1e-8)
  23. {
  24. double x=(l+r)/2;
  25. if (x*x*x>=a) r=x;
  26. else l=x;
  27. }
  28. printf("%.6lf\n", l);
  29. }
  30. else if (a==0) cout <<"0.000000"<<endl;
  31. return 0;
  32. }

730. 机器人跳跃问题(二分)(递推)

链接:730. 机器人跳跃问题 - AcWing题库

描述: 

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. const int N = 100010;
  7. int n;
  8. int h[N];
  9. bool check(int e)
  10. {
  11. for (int i = 1; i <= n; i ++ )
  12. {
  13. e = e * 2 - h[i];
  14. if (e >= 1e5) return true;
  15. if (e < 0) return false;
  16. }
  17. return true;
  18. }
  19. int main()
  20. {
  21. scanf("%d", &n);
  22. for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]);
  23. int l = 0, r = 1e5;
  24. while (l < r)
  25. {
  26. int mid = l + r >> 1;
  27. if (check(mid)) r = mid;
  28. else l = mid + 1;
  29. }
  30. printf("%d\n", r);
  31. return 0;
  32. }

收获: 

1.Mid=(l+r)/2

r=mid

else l=mid+1

或者

Mid=(l+r)/2 +1

r=mid -1

else l=mid

2.做题一般都是先看直觉(暴力)(枚举)学过的哪些算法可以优化 顺序一般就是 二分 dfs dp 贪心

3.根据题目分析得出 递推或者关键的一些公式很有用

4.根据一套相关知识点的题 提高对这一个知识点的理解(很有用

5.有些细节的东西只需要仔细想一遍就可以了 ,以后不用反复想,直接用或者背。(回想之前擅长物理也是这样,那些公式和关键的东西想明白一遍就可以了)

1221. 四平方和(二分)(哈希)

链接:

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

闽ICP备14008679号