当前位置:   article > 正文

第十四届蓝桥杯大赛软件赛省赛Java 大学 C 组_2.分糖果 两种糖果分别有9个和16个,要全部分给7个小朋友,每个小朋友得到的糖果总p

2.分糖果 两种糖果分别有9个和16个,要全部分给7个小朋友,每个小朋友得到的糖果总p

目录

试题 A: 求和

试题 B: 分糖果

试题 C: 三国游戏

试题 D: 平均

试题 E: 填充

试题 F: 棋盘

试题 G: 子矩阵

试题 H: 公因数匹配

试题 I: 异或和之差

 试题 J: 太阳


 蓝桥杯ACM训练系统 - C语言网 (dotcpp.com) 以及 题库 - AcWing上可过

试题 A: 求和

本题总分: 5
【问题描述】
1 (含)至 20230408 (含)中每个数的和。
我的答案 :204634714038436

试题 B: 分糖果

本题总分: 5
【问题描述】
两种糖果分别有 9 个和 16 个,要全部分给 7 个小朋友,每个小朋友得到
的糖果总数最少为 2 个最多为 5 个,问有多少种不同的分法。
只要有其中一个小朋友在两种方案中分到的糖果不完全相同,这两种方案
就算作不同的方案
我们可以直接dfs暴力求解,我的答案 5067671
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. const int maxn=1e2+10;
  9. ll ans=0;
  10. void dfs(int sum1,int sum2,int cnt)
  11. {
  12. if(sum1<0||sum2<0)return;
  13. if(cnt==7)
  14. {
  15. if(sum1==0&&sum2==0)ans++;
  16. return;
  17. }
  18. for(int i=0;i<=sum1;i++)
  19. {
  20. for(int j=0;j<=sum2;j++)
  21. {
  22. if(i+j>=2&&i+j<=5)
  23. {
  24. dfs(sum1-i,sum2-j,cnt+1);
  25. }
  26. }
  27. }
  28. }
  29. void solve()
  30. {
  31. dfs(9,16,0);
  32. cout<<ans<<endl;
  33. }
  34. int main()
  35. {
  36. ios::sync_with_stdio(0);
  37. cin.tie(0);
  38. cout.tie(0);
  39. int tn=1;
  40. //cin>>tn;
  41. while(tn--)
  42. {
  43. solve();
  44. }
  45. return 0;
  46. }

试题 C: 三国游戏

时间限制 : 3.0s
内存限制 : 512.0MB
本题总分: 10
【问题描述】
小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵
X , Y , Z ( 一开始可以认为都为 0 ) 。游戏有 n 个可能会发生的事件,每个事件之
间相互独立且最多只会发生一次,当第 i 个事件发生时会分别让 X , Y , Z 增加
A i , B i , C i
当游戏结束时 ( 所有事件的发生与否已经确定 ) ,如果 X , Y , Z 的其中一个大
于另外两个之和,我们认为其获胜。例如,当 X > Y + Z 时,我们认为魏国获
胜。小蓝想知道游戏结束时如果有其中一个国家获胜,最多发生了多少个事件 ?
如果不存在任何能让某国获胜的情况,请输出 1
【输入格式】
输入的第一行包含一个整数 n
第二行包含 n 个整数表示 A i ,相邻整数之间使用一个空格分隔。
第三行包含 n 个整数表示 B i ,相邻整数之间使用一个空格分隔。
第四行包含 n 个整数表示 C i ,相邻整数之间使用一个空格分隔。
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
3
1 2 2
2 3 2
1 0 7
【样例输出】
2
【样例说明】
发生两个事件时,有两种不同的情况会出现获胜方。
发生 1 , 2 事件时蜀国获胜。
发生 1 , 3 事件时吴国获胜。
【评测用例规模与约定】
对于 40 % 的评测用例, n 500
对于 70 % 的评测用例, n 5000
对于所有评测用例, 1 n 10 5 1 A i , B i , C i 10 9
贪心,对于每个国家我们都重新排序这n个事件,比如我是魏国,那我按照x-y-z从大到小排序,
然后统计答案即可
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. const int maxn=1e5+10;
  9. struct node
  10. {
  11. ll x,y,z;
  12. };
  13. bool cmp1(node &a,node &b)
  14. {
  15. return a.x-(a.y+a.z)>b.x-(b.y+b.z);
  16. }
  17. bool cmp2(node &a,node &b)
  18. {
  19. return a.y-(a.x+a.z)>b.y-(b.x+b.z);
  20. }
  21. bool cmp3(node &a,node &b)
  22. {
  23. return a.z-(a.y+a.x)>b.z-(b.y+b.x);
  24. }
  25. int n;
  26. node a[maxn],b[maxn],c[maxn];
  27. void solve()
  28. {
  29. cin>>n;
  30. for(int i=1;i<=n;i++)
  31. {
  32. cin>>a[i].x;
  33. b[i].x=c[i].x=a[i].x;
  34. }
  35. for(int i=1;i<=n;i++)
  36. {
  37. cin>>a[i].y;
  38. b[i].y=c[i].y=a[i].y;
  39. }
  40. for(int i=1;i<=n;i++)
  41. {
  42. cin>>a[i].z;
  43. b[i].z=c[i].z=a[i].z;
  44. }
  45. sort(a+1,a+n+1,cmp1);
  46. sort(b+1,b+n+1,cmp2);
  47. sort(c+1,c+n+1,cmp3);
  48. ll ans=-1;
  49. for(ll i=1,x=0,y=0,z=0;i<=n;i++)
  50. {
  51. x+=a[i].x;
  52. y+=a[i].y;
  53. z+=a[i].z;
  54. if(x>y+z)
  55. {
  56. ans=max(ans,i);
  57. }
  58. }
  59. for(ll i=1,x=0,y=0,z=0;i<=n;i++)
  60. {
  61. x+=b[i].x;
  62. y+=b[i].y;
  63. z+=b[i].z;
  64. if(y>x+z)
  65. {
  66. ans=max(ans,i);
  67. }
  68. }
  69. for(ll i=1,x=0,y=0,z=0;i<=n;i++)
  70. {
  71. x+=c[i].x;
  72. y+=c[i].y;
  73. z+=c[i].z;
  74. if(z>y+x)
  75. {
  76. ans=max(ans,i);
  77. }
  78. }
  79. cout<<ans<<endl;
  80. }
  81. int main()
  82. {
  83. ios::sync_with_stdio(0);
  84. cin.tie(0);
  85. cout.tie(0);
  86. int tn=1;
  87. //cin>>tn;
  88. while(tn--)
  89. {
  90. solve();
  91. }
  92. return 0;
  93. }

试题 D: 平均

时间限制 : 3.0s
内存限制 : 512.0MB
本题总分: 10
【问题描述】
有一个长度为 n 的数组(
n 10 的倍数),每个数 a i 都是区间 [0 , 9] 中的
整数。小明发现数组里每种数出现的次数不太平均,而更改第 i 个数的代价为
b i ,他想更改若干个数的值使得这 10 种数出现的次数相等(都等于
n
10
),请问
代价和最少为多少。
【输入格式】
输入的第一行包含一个正整数 n
接下来 n 行,第 i 行包含两个整数 a i , b i ,用一个空格分隔。
【输出格式】
输出一行包含一个正整数表示答案。
【样例输入】
10
1 1
1 2
1 3
2 4
2 5
2 6
3 7
3 8
3 9
4 10
【样例输出】
27
【样例说明】
只更改第 1 , 2 , 4 , 5 , 7 , 8 个数,需要花费代价 1 + 2 + 4 + 5 + 7 + 8 = 27
【评测用例规模与约定】
对于 20 % 的评测用例, n 1000
对于所有评测用例, n 100000 , 0 < b i 2 × 10 5

贪心,按找b从小到大,然后遇到大于n/10的我就把它变成其他数

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. const int maxn=1e5+10;
  9. struct node
  10. {
  11. int a,b;
  12. bool operator<(const node &o)const
  13. {
  14. return b<o.b;
  15. }
  16. };
  17. int n;
  18. node ai[maxn];
  19. int cnt[20];
  20. void solve()
  21. {
  22. cin>>n;
  23. for(int i=1;i<=n;i++)
  24. {
  25. cin>>ai[i].a>>ai[i].b;
  26. cnt[ai[i].a]++;
  27. }
  28. sort(ai+1,ai+n+1);
  29. ll ans=0,f=n/10;
  30. for(int i=1;i<=n;i++)
  31. {
  32. if(cnt[ai[i].a]>f)
  33. {
  34. for(int j=0;j<=9;j++)
  35. {
  36. if(cnt[j]<f)
  37. {
  38. cnt[ai[i].a]--;
  39. cnt[j]++;
  40. ans=ans+ai[i].b;
  41. break;
  42. }
  43. }
  44. }
  45. }
  46. cout<<ans<<endl;
  47. }
  48. int main()
  49. {
  50. ios::sync_with_stdio(0);
  51. cin.tie(0);
  52. cout.tie(0);
  53. int tn=1;
  54. //cin>>tn;
  55. while(tn--)
  56. {
  57. solve();
  58. }
  59. return 0;
  60. }

试题 E: 填充

时间限制 : 3.0s
内存限制 : 512.0MB
本题总分: 15
【问题描述】
有一个长度为 n 01 串,其中有一些位置标记为 ? ,这些位置上可以任意
填充 0 或者 1 ,请问如何填充这些位置使得这个 01 串中出现互不重叠的 00
11 子串最多,输出子串个数。
【输入格式】
输入一行包含一个字符串。
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
1110?0
【样例输出】
2
【样例说明】
如果在问号处填 0 ,则最多出现一个 00 和一个 11 111000
【评测用例规模与约定】
对于所有评测用例, 1 n 1000000
贪心,其实由于不交叉,那么遇到?我们就当作0,1都加了就可以,然后遇到0,1计数等于2就统计答案并清空
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. const int maxn=1e6+10;
  9. int n;
  10. char a[maxn];
  11. int f[maxn];
  12. void solve()
  13. {
  14. cin>>a+1;
  15. n=strlen(a+1);
  16. int ans=0,cnt1=0,cnt0=0;
  17. for(int i=1;i<=n;i++)
  18. {
  19. if(a[i]=='1')
  20. {
  21. cnt1++;cnt0=0;
  22. }else if(a[i]=='0')
  23. {
  24. cnt0++;cnt1=0;
  25. }else if(a[i]=='?')
  26. {
  27. if(cnt1==1)
  28. {
  29. cnt1++;
  30. }else if(cnt0==1)
  31. {
  32. cnt0++;
  33. }else
  34. {
  35. cnt1++;cnt0++;
  36. }
  37. }
  38. //cout<<cnt1<<" "<<cnt0<<endl;
  39. if(cnt1==2||cnt0==2)
  40. {
  41. ans++;
  42. cnt1=0;cnt0=0;
  43. }
  44. }
  45. cout<<ans<<endl;
  46. }
  47. int main()
  48. {
  49. ios::sync_with_stdio(0);
  50. cin.tie(0);
  51. cout.tie(0);
  52. int tn=1;
  53. //cin>>tn;
  54. while(tn--)
  55. {
  56. solve();
  57. }
  58. return 0;
  59. }

试题 F: 棋盘

时间限制 : 3.0s
内存限制 : 512.0MB
本题总分: 15
【问题描述】
小蓝拥有 n × n 大小的棋盘,一开始棋盘上全都是白子。小蓝进行了 m
操作,每次操作会将棋盘上某个范围内的所有棋子的颜色取反 ( 也就是白色棋
子变为黑色,黑色棋子变为白色 ) 。请输出所有操作做完后棋盘上每个棋子的颜
色。
【输入格式】
输入的第一行包含两个整数 n , m ,用一个空格分隔,表示棋盘大小与操作
数。
接下来 m 行每行包含四个整数 x 1 , y 1 , x 2 , y 2 ,相邻整数之间使用一个空格分
隔,表示将在 x 1 x 2 行和 y 1 y 2 列中的棋子颜色取反。
【输出格式】
输出 n 行,每行 n 0 1 表示该位置棋子的颜色。如果是白色则输出 0
,否则输出 1
【样例输入】
3 3
1 1 2 2
2 2 3 3
1 1 3 3
【样例输出】
001
010
100
【评测用例规模与约定】
对于 30 % 的评测用例, n m 500
对于所有评测用例, 1 n , m 2000 1 x 1 x 2 n 1 y 1 y 2 m
二维差分 对于每个矩阵,我们都让矩阵内的值+1,最后如果这个位置是奇数就是黑棋,否则白棋
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. const int maxn=2e3+10;
  9. int n,m;
  10. int a[maxn][maxn];
  11. void solve()
  12. {
  13. cin>>n>>m;
  14. for(int i=1,x1,y1,x2,y2;i<=m;i++)
  15. {
  16. cin>>x1>>y1>>x2>>y2;
  17. if(x1>x2)swap(x1,x2);
  18. if(y1>y2)swap(y1,y2);
  19. a[x1][y1]++;
  20. a[x1][y2+1]--;
  21. a[x2+1][y1]--;
  22. a[x2+1][y2+1]++;
  23. }
  24. for(int i=1;i<=n;i++)
  25. {
  26. for(int j=1;j<=n;j++)
  27. {
  28. a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
  29. if(a[i][j]&1)cout<<"1";
  30. else cout<<"0";
  31. }
  32. cout<<endl;
  33. }
  34. }
  35. int main()
  36. {
  37. ios::sync_with_stdio(0);
  38. cin.tie(0);
  39. cout.tie(0);
  40. int tn=1;
  41. //cin>>tn;
  42. while(tn--)
  43. {
  44. solve();
  45. }
  46. return 0;
  47. }

试题 G: 子矩阵

时间限制 : 5.0s
内存限制 : 512.0MB
本题总分: 20
【问题描述】
给定一个 n × m
n m 列)的矩阵。
设一个矩阵的价值为其所有数中的最大值和最小值的乘积。求给定矩阵的
所有大小为 a × b
a b 列)的子矩阵的价值的和。
答案可能很大,你只需要输出答案对 998244353 取模后的结果。
【输入格式】
输入的第一行包含四个整数分别表示 n , m , a , b ,相邻整数之间使用一个空
格分隔。
接下来 n 行每行包含 m 个整数,相邻整数之间使用一个空格分隔,表示矩
阵中的每个数 A i , j
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
2 3 1 2
1 2 3
4 5 6
【样例输出】
58
【样例说明】
1 × 2 + 2 × 3 + 4 × 5 + 5 × 6 = 58
【评测用例规模与约定】
对于 40 % 的评测用例, 1 n , m 100
对于 70 % 的评测用例, 1 n , m 500
对于所有评测用例, 1 a n 1000 1 b m 1000 1 A i , j 10 9

单调队列,或者线段树

先维护每个位置前b列的最大最小值,然后再在新矩阵上跑,每个位置前a行的最大最小值,那么不就求的了以每个位置为右下角的a*b的矩阵了嘛

单调队列维护复杂度O(N*N),线段树O(N*N*logN)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. #define big __int128
  9. const ll mod=998244353 ;
  10. const int maxn=1e3+10;
  11. int n,m,x,y;
  12. ll a[maxn][maxn];
  13. ll heng[maxn][maxn];
  14. ll shu[maxn][maxn];
  15. ll st[maxn],id[maxn];
  16. int s=0,e=0;
  17. void solve()
  18. {
  19. cin>>n>>m>>x>>y;
  20. for(int i=1;i<=n;i++)
  21. {
  22. for(int j=1;j<=m;j++)
  23. {
  24. cin>>a[i][j];
  25. }
  26. }
  27. for(int i=1;i<=n;i++)//维护i,j位置(j-b+1,j)之间最小值
  28. {
  29. s=1;e=1;
  30. st[e]=a[i][1];
  31. id[e]=1;
  32. for(int j=1;j<=m;j++)
  33. {
  34. while(s<=e&&id[s]<j-y+1)s++;
  35. while(s<=e&&st[e]>=a[i][j])e--;
  36. st[++e]=a[i][j];
  37. id[e]=j;
  38. heng[i][j]=st[s];
  39. }
  40. }
  41. for(int j=1;j<=m;j++)//维护i,j位置往上a,b矩阵的之间最小值
  42. {
  43. s=1;e=1;
  44. st[e]=heng[1][j];
  45. id[e]=1;
  46. for(int i=1;i<=n;i++)
  47. {
  48. while(s<=e&&id[s]<i-x+1)s++;
  49. while(s<=e&&st[e]>=heng[i][j])e--;
  50. st[++e]=heng[i][j];
  51. id[e]=i;
  52. shu[i][j]=st[s];
  53. }
  54. }
  55. for(int i=1;i<=n;i++)//维护i,j位置(j-b+1,j)之间最大值
  56. {
  57. s=1;e=1;
  58. st[e]=a[i][1];
  59. id[e]=1;
  60. for(int j=1;j<=m;j++)
  61. {
  62. while(s<=e&&id[s]<j-y+1)s++;
  63. while(s<=e&&st[e]<=a[i][j])e--;
  64. st[++e]=a[i][j];
  65. id[e]=j;
  66. heng[i][j]=st[s];
  67. }
  68. }
  69. ll ans=0;
  70. for(int j=1;j<=m;j++)//维护i,j位置往上a,b矩阵的之间最大值,并计算答案
  71. {
  72. s=1;e=1;
  73. st[e]=heng[1][j];
  74. id[e]=1;
  75. for(int i=1;i<=n;i++)
  76. {
  77. while(s<=e&&id[s]<i-x+1)s++;
  78. while(s<=e&&st[e]<=heng[i][j])e--;
  79. st[++e]=heng[i][j];
  80. id[e]=i;
  81. if(i>=x&&j>=y)ans=(ans+shu[i][j]*st[s]%mod)%mod;
  82. }
  83. }
  84. cout<<ans<<endl;
  85. }
  86. int main()
  87. {
  88. ios::sync_with_stdio(0);
  89. cin.tie(0);
  90. cout.tie(0);
  91. int tn=1;
  92. //cin>>tn;
  93. while(tn--)
  94. {
  95. solve();
  96. }
  97. return 0;
  98. }

试题 H: 公因数匹配

时间限制 : 3.0s
内存限制 : 512.0MB
本题总分: 20
【问题描述】
给定 n 个正整数 A i ,请找出两个数 i , j 使得 i < j A i A j 存在大于 1
公因数。
如果存在多组 i , j ,请输出 i 最小的那组。如果仍然存在多组 i , j ,请输出 i
最小的所有方案中 j 最小的那组。
【输入格式】
输入的第一行包含一个整数 n
第二行包含 n 个整数分别表示 A 1 A 2 · · · A n ,相邻整数之间使用一个空格
分隔。
【输出格式】
输出一行包含两个整数分别表示题目要求的 i , j ,用一个空格分隔。
【样例输入】
5
5 3 2 6 9
【样例输出】
2 4
【评测用例规模与约定】
对于 40 % 的评测用例, n 5000
对于所有评测用例, 1 n 10 5 1 A i 10 6
正常暴力N*N是不行的,然后我们考虑优化,其实只用枚举质数,然后通过埃氏筛选择这样就可以
在O(K*N*lnN)复杂度下实现,这里K是这个数的质因子个数,最坏情况就是全是这个质因子个数的数
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. const int maxn=1e6+10;
  9. int n;
  10. int f[maxn];
  11. vector<int>v[maxn];
  12. void solve()
  13. {
  14. cin>>n;
  15. for(int i=1,j;i<=n;i++)
  16. {
  17. cin>>j;
  18. v[j].pd(i);
  19. }
  20. for(int i=1;i<=1000000;i++)
  21. {
  22. sort(v[i].begin(),v[i].end());
  23. }
  24. int l=maxn,r=maxn;
  25. for(int i=2;i<=1000000;i++)
  26. {
  27. if(!f[i])
  28. {
  29. vector<int>ans;
  30. for(auto id:v[i])
  31. {
  32. ans.pd(id);
  33. }
  34. for(int j=i+i;j<=1000000;j+=i)
  35. {
  36. f[j]=1;
  37. for(auto id:v[j])
  38. {
  39. ans.pd(id);
  40. }
  41. }
  42. if(ans.size()>=2)
  43. {
  44. sort(ans.begin(),ans.end());
  45. if(l>ans[0])
  46. {
  47. l=ans[0];
  48. r=ans[1];
  49. }else if(l==ans[0]&&r>ans[1])
  50. {
  51. r=ans[1];
  52. }
  53. }
  54. }
  55. }
  56. cout<<l<<" "<<r;
  57. }
  58. int main()
  59. {
  60. ios::sync_with_stdio(0);
  61. cin.tie(0);
  62. cout.tie(0);
  63. int tn=1;
  64. //cin>>tn;
  65. while(tn--)
  66. {
  67. solve();
  68. }
  69. return 0;
  70. }

试题 I: 异或和之差

时间限制 : 3.0s
内存限制 : 512.0MB
本题总分: 25
【问题描述】
给定一个含有 n 个元素的数组 A i ,你可以选择两个不相交的子段。求出这
两个子段内的数的异或和的差值的最大值。
【输入格式】
输入的第一行包含一个整数 n
第二行包含 n 个整数 A i ,相邻整数之间使用一个空格分隔。
【输出格式】
输出一行包含一个整数表示答案。
【样例输入】
6
1 2 4 9 2 7
【样例输出】
14
【样例说明】
两个子段可以分别选 1 4 9 2 ,差值为 15 1 = 14
【评测用例规模与约定】
对于 40 % 的评测用例, n 5000
对于所有评测用例, 2 n 2 × 10 5 0 A i 2 20

01字典树,前缀和

01字典树内存前缀异或的值,然后查询最大最小值,不就得到了以这个位置为末尾的区间最大最小异或值,记得要先加入个0,表示区间不去

后缀异或同理

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. const int maxn=2e5+10;
  9. struct tree01
  10. {
  11. int tot;
  12. int ch[maxn<<5][2];
  13. void init()
  14. {
  15. for(int i=0;i<=tot;i++)ch[i][0]=ch[i][1]=0;
  16. }
  17. void add(int x)
  18. {
  19. int u=0;
  20. for(int i=20;i>=0;i--)
  21. {
  22. int t=(x>>i)&1;
  23. if(!ch[u][t])
  24. {
  25. ch[u][t]=++tot;
  26. }
  27. u=ch[u][t];
  28. }
  29. }
  30. int querymx(int x)
  31. {
  32. int u=0;
  33. int ans=0;
  34. for(int i=20;i>=0;i--)
  35. {
  36. int t=(x>>i)&1;
  37. if(ch[u][t^1])
  38. {
  39. u=ch[u][t^1];
  40. ans+=(1<<i);
  41. }else
  42. {
  43. u=ch[u][t];
  44. }
  45. }
  46. return ans;
  47. }
  48. int querymi(int x)
  49. {
  50. int u=0;
  51. int ans=0;
  52. for(int i=20;i>=0;i--)
  53. {
  54. int t=(x>>i)&1;
  55. if(ch[u][t])
  56. {
  57. u=ch[u][t];
  58. }else
  59. {
  60. u=ch[u][t^1];
  61. ans+=(1<<i);
  62. }
  63. }
  64. return ans;
  65. }
  66. }tree01;
  67. int n;
  68. int a[maxn];
  69. int rmx[maxn],rmi[maxn];//[1,R]区间内的异或最大值最小值
  70. int lmx[maxn],lmi[maxn];//[L,n]区间内的异或最大值最小值
  71. void solve()
  72. {
  73. cin>>n;
  74. for(int i=0;i<=n+1;i++)
  75. {
  76. rmi[i]=lmi[i]=1e9;
  77. }
  78. tree01.tot=0;
  79. tree01.add(0);//先加个0表示区间不取
  80. for(int i=1,sum=0;i<=n;i++)
  81. {
  82. cin>>a[i];
  83. sum^=a[i];
  84. rmx[i]=max(rmx[i-1],tree01.querymx(sum));
  85. rmi[i]=min(rmi[i-1],tree01.querymi(sum));
  86. tree01.add(sum);
  87. //cout<<rmx[i]<<" "<<rmi[i]<<endl;
  88. }
  89. tree01.init();
  90. tree01.tot=0;
  91. tree01.add(0);//先加个0表示区间不取
  92. for(int i=n,sum=0;i>=1;i--)
  93. {
  94. sum^=a[i];
  95. lmx[i]=max(lmx[i+1],tree01.querymx(sum));
  96. lmi[i]=min(lmi[i+1],tree01.querymi(sum));
  97. tree01.add(sum);
  98. //cout<<rmx[i]<<" "<<rmi[i]<<endl;
  99. }
  100. int ans=0;
  101. for(int i=1;i<n;i++)
  102. {
  103. ans=max(ans,rmx[i]-lmi[i+1]);
  104. ans=max(ans,lmx[i+1]-rmi[i]);
  105. // cout<< rmx[i] << " "<< lmi[i+1] <<" "<< lmx[i]<<" "<<rmi[i-1]<<"\n";
  106. }
  107. cout<<ans<<endl;
  108. }
  109. int main()
  110. {
  111. ios::sync_with_stdio(0);
  112. cin.tie(0);
  113. cout.tie(0);
  114. int tn=1;
  115. //cin>>tn;
  116. while(tn--)
  117. {
  118. solve();
  119. }
  120. return 0;
  121. }

 试题 J: 太阳

时间限制 : 3.0s
内存限制 : 512.0MB
本题总分: 25
【问题描述】
这天,小蓝在二维坐标系的点 ( X , Y ) 上放了一个太阳,看做点光源。
他拿来了 n 条线段,将它们平行于 x 轴放置在了坐标系中,第 i 条线段的
左端点在 x i , y i ,长度为 l i 。线段之间不会有重合或部分重合的情况(但可能出
现端点相交)。小蓝想知道有多少条线段能被太阳照亮(一条线段有长度大于 0
的部分被照亮就算)。
【输入格式】
输入的第一行包含三个正整数 n , X , Y ,相邻整数之间使用一个空格分隔。
接下来 n 行,第 i 行包含三个整数 x i , y i , l i ,相邻整数之间使用一个空格分
隔。
【输出格式】
输出一行包含一个正整数表示答案。
【样例输入】
3 10 2000000
5 3 5
6 2 4
0 1 10
【样例输出】
2
【样例说明】
第一条线段在最上面被照亮,第二条线段被第一条完全挡住,第三条线段
左边的一段能被照亮。
【评测用例规模与约定】
对于 30 % 的评测用例, n 1000
对于所有评测用例, 1 n 100000 , 0 x i , X 10 7 , 0 < y i 10 5 , 0 < l i
100 , 10 6 < Y 10 7

把线段投射到y=0的位置,然后按照y排序,区间覆盖

由于区间端点会是小数,我采用了珂朵莉树

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define endl '\n'
  5. #define x first
  6. #define y second
  7. #define pd push_back
  8. #define pii pair<double,double>
  9. #define It set<ran>::iterator
  10. const int maxn=1e5+10;
  11. const double inf=1e15;
  12. struct ran{
  13. double l, r;
  14. mutable int v;//mutable 关键字定义一个强制可变量
  15. bool operator <(const ran &x)const{//运算符重载,用于set的排序
  16. return l < x.l;//按区间的左端点从小到大来排
  17. }
  18. };
  19. struct ODT
  20. {
  21. set<ran>tr;//珂朵莉树的定义
  22. int ans=0;
  23. It split(double pos)
  24. {
  25. It it = tr.lower_bound({pos, -1, 0});//找到所需的pos的迭代器
  26. if(it != tr.end() && it->l == pos)return it;//看看这个迭代器的l是不是所需要的pos,是的话直接返回就行
  27. --it;//不是的话就说明肯定是在前一个里面
  28. double l = it->l;
  29. double r = it->r;
  30. int v = it->v;
  31. tr.erase(it);//我们删掉这个区间
  32. tr.insert({l, pos - 1, v});//重新塞入两个区间[l, pos -1 ],[pos, r]
  33. return tr.insert({pos, r, v}).first;//返回以pos开头的区间的迭代器
  34. }
  35. void emerge(double l, double r, int x)
  36. {
  37. It itr = split(r + 1e-15), itl = split(l);//先找到r+1的迭代器位置,再找l的迭代器位置
  38. //操作
  39. It it=itl;
  40. int f=0;
  41. for(;it!=itr;++it)
  42. {
  43. if((it->v)==0)f=1;
  44. }
  45. ans+=f;
  46. //操作
  47. tr.erase(itl, itr);//删掉这一段迭代器
  48. tr.insert({l, r, x});//重新插入所需区间
  49. }
  50. }odt;
  51. struct node
  52. {
  53. double x1,x2,y;
  54. bool operator<(const node&o)const
  55. {
  56. return y>o.y;
  57. }
  58. };
  59. int n;
  60. double X,Y;
  61. node a[maxn];
  62. double to0(int x,int y)
  63. {
  64. if(x==X)return x;
  65. double k=(Y-y)/(X-x);
  66. double b=k*X-Y;
  67. return b/k;
  68. }
  69. void solve()
  70. {
  71. cin>>n>>X>>Y;
  72. for(int i=1;i<=n;i++)
  73. {
  74. cin>>a[i].x1>>a[i].y>>a[i].x2;
  75. a[i].x2+=a[i].x1;
  76. a[i].x1=to0(a[i].x1,a[i].y);
  77. a[i].x2=to0(a[i].x2,a[i].y);
  78. }
  79. sort(a+1,a+n+1);
  80. //区间覆盖,我选择珂朵莉树
  81. odt.tr.insert({-inf,inf,0});
  82. for(int i=1;i<=n;i++)
  83. {
  84. odt.emerge(a[i].x1,a[i].x2,1);
  85. }
  86. cout<<odt.ans<<endl;
  87. }
  88. int main()
  89. {
  90. ios::sync_with_stdio(0);
  91. cin.tie(0);
  92. cout.tie(0);
  93. int tn=1;
  94. //cin>>tn;
  95. while(tn--)
  96. {
  97. solve();
  98. }
  99. return 0;
  100. }

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

闽ICP备14008679号