CSDN竞赛11期题解
迪丽瓦拉
2024-04-14 22:54:29
0

总结

本次竞赛题目没有出现明显的bug,题目比较简单,大都考察阅读理解能力。除了在T1T_1T1​上被π\piπ的精度卡了很久,其他题目做起来都比较容易。另外,输入模板部分题目输入读入string后采取了stoi进行转换,部分题目依旧使用string作为模板函数的输入,这点还需要改进。

题目列表

1.圆小艺

题目描述

最近小艺酱渐渐变成了一个圆滑的形状-球!!
小艺酱开始变得喜欢上球!
小艺酱得到n个同心圆。
小艺酱对着n个同心圆进行染色。
相邻的圆范围内不能有相同的颜色。相隔一层的圆颜色相同。
小艺酱想知道两种颜色最大中最外层圆的那种颜色染了多少?

输入描述:

第一行输入整数n.(1<=n<=1000)表示圆的数量。
第二行输入n个圆的半径。(1<=r<=1000)

输出描述:

输出染色面积,保留小数点后3位。

输入样例:

3
1 2 3

输出样例:

18.849

分析

本次竞赛的压轴题,为啥这么说呢?这题卡π\piπ的的精度。即使写3.1415926533.1415926533.141592653都只能通过九成用例,卡了我很久后改成acos(−1)acos(-1)acos(−1)才AC。

考察阅读理解的模拟题,将圆按照半径排序后,自大而小的计算面积。设同心圆的面积自小而大依次是S1,S2,...,SnS_1,S_2,...,S_nS1​,S2​,...,Sn​,染色面积等于Sn−Sn−1+Sn−2−...+(−1)n+1∗S1S_n -S_{n-1}+S_{n-2}-...+(-1)^{n+1}*S_1Sn​−Sn−1​+Sn−2​−...+(−1)n+1∗S1​。

代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const double PI = acos(-1);
double solution(int n, std::vector& vec) {sort(vec.begin(),vec.end());double res = 0;int t = 1;for(int i = n - 1; i >= 0; i--) {double x = vec[i];res += x * x * t;t = -t;}return res;
}
int main() {int n;std::vector vec;std::cin>>n;int x;for(int i = 0; i < n; i++) {cin>>x;vec.push_back(x);}double result = solution(n,vec);printf("%.3lf\n",result*PI);return 0;
}

2.K皇把妹

题目描述

存在n个节点,目标节点在m。
每个节点有自己的权值a。
在权值k内选择一个权值非0节点且与目标节点距离最近。
节点i与节点j的距离为abs(i-j)。

输入描述:

第一行输入整数n,m,k.(1<=n,m,k<=100)
第二行输入n个整数的权值。(1<=a<=1000)

输出描述:

输出最小距离

输入样例:

7 3 50
62 0 0 0 99 33 22

输出样例:

3

分析

考察阅读理解的模拟题,翻译一下就是有一个线性序列a1,a2,...,ak,...,ana_1,a_2,...,a_k,...,a_na1​,a2​,...,ak​,...,an​,我们在这个序列里找离aka_kak​最近的并且值在(0,k](0,k](0,k]之间的元素,输出二者之间的距离即可。只需要我们从aka_kak​开始向左和向右逐个遍历,找到符合要求的元素为止。

代码

#include 
#include 
#include 
#include 
using namespace std;
int solution(int n, int m, int k, std::vector& vec) {int p = m - 1;int i = p,j = p;while(true) {if(i >= 0 && vec[i] && vec[i] <= k) return (p - i);if(j < n && vec[j] && vec[j] <= k) return j - p;i--,j++;}return -1;
}
int main() {int n;int m;int k;std::vector vec;std::cin>>n;std::cin>>m;std::cin>>k;std::string line_0, token_0;getline(std::cin >> std::ws,line_0);std::stringstream tokens_0(line_0);while(std::getline(tokens_0, token_0, ' ')) {vec.push_back(std::stoi(token_0));}int result = solution(n, m, k,vec);std::cout<

3. 筛选宝物

题目描述

已知存在n个宝物,每个宝物都有自己的质量m和价值v,在考虑选择宝物时只能选择总质量小于等于M的方案,请问在最 优方案下选择宝物,能获取到最大价值V是多少?

分析

01背包问题裸题,具体解析可以参考AcWing201背包问题AcWing\ 2\ 01背包问题AcWing 2 01背包问题。

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;
int f[105][1005];
int solution(int n, int M, std::vector>& vec) {for (int i = 1; i <= n; i++) {for(int j = 0; j <= M; j++) {f[i][j] = f[i-1][j];if(j >= vec[i-1][0]) f[i][j] = max(f[i][j],f[i-1][j-vec[i-1][0]] + vec[i-1][1]);}}int res = 0;for(int i = 1; i <= M; i++) res = max(res,f[n][i]);return res;
}
int main() {int n;int M;std::vector> vec;std::cin>>n;std::cin>>M;std::string line, token;for (int i = 0; i < n; i++) {int a,b;cin>>a>>b;vec.push_back({a,b});}int result = solution(n, M,vec);std::cout<

4.题目名称:圆桌

题目描述

有N个客人与足够多张的圆桌。主人安排每位客人坐在一个圆桌边,但是每位客人希望自己左右边上分别有一些空座位,不然会觉得害羞。注意,如果一个客人所在的圆桌只有他一个人,那么他左边的空座位数量就是他右边的空座位数量。
试问主人需要准备多少个座位,才能让每个客人舒适的坐下。

输入描述:

第一行输入一个整数N,(1<=N<=10000),代表客人的数量
接下来N行,每行两个整数li与ri,(1<=i<=N,1<=li<=ri<=1000000000)
代表第i位客人希望左边有li个空座位,右边有ri个空座位。

输出描述:

输出一个整数,代表主人需要准备的最少座位数量。

输入样例:

3
1 1
1 1
1 1

输出样例:

6

分析

贪心的问题总是代码简洁,但是证明复杂。首先,要注意题目中的有足够多圆桌的含义,这意味着最多可以准备n张圆桌,让每个人都独坐一桌。对于第一个客人而言,要么独坐一桌,要么与他人合坐。独坐一桌的话,除了他自己坐的椅子,还需要放上max(l1,r1)max(l1,r1)max(l1,r1)个椅子;与他人合坐的话,假设第二个人坐在他右边,那么,其右边最少需要放max(l2,r1)max(l2,r1)max(l2,r1)个椅子。不论是哪种情况,某个桌子上,若干个客人坐成一圈,每个人右边的椅子数量都取决于其希望右边放置的椅子数量和右边客人希望左边放置的椅子数量的大小。如果jjj坐在iii右边,我们就说rir_iri​与ljl_jlj​是配对的,配对的椅子数量是k=max(ri,lj)k\ =\ max(r_i,l_j)k = max(ri​,lj​)。例如ri=3,lj=5r_i=3,\ l_j=5ri​=3, lj​=5。那么在中间放置5张椅子,对于iii而言,有两张椅子是多余的,我们希望这种多余的椅子越少越好,对于每个客人而言,就是希望与其rrr配对的lll之间越接近越好。

但是天不遂人愿,如果有一个lll,有两个rrr都想与之配对,那么注定有一人要失望了。比如l=3l=3l=3,有两个rrr分别是4和5的两个客人,离他们最近的lll就是3,那么要使用什么策略才能让准备的椅子最少呢?假设lll和rrr的集合里分别有l1l_1l1​,l2l_2l2​,r1r_1r1​,r2r_2r2​(这些lll和rrr可以来自不同的客人)。什么样的排列顺序需要的椅子最少呢?有以下两种策略:

  • l1l_1l1​与r1r_1r1​配对,需要额外添加的椅子数等于a=max(l1,r1)+max(l2,r2)a=max(l1,r1) + max(l2,r2)a=max(l1,r1)+max(l2,r2)
  • l1l_1l1​与r2r_2r2​配对,需要额外添加的椅子数等于b=max(l1,r2)+max(l2,r1)b=max(l1,r2) + max(l2,r1)b=max(l1,r2)+max(l2,r1)

不妨设其中最大值是r1r1r1,那么a=r1+max(l2,r2)a=r1 + max(l2,r2)a=r1+max(l2,r2),b=r1+max(l1,r2)b=r1+max(l1,r2)b=r1+max(l1,r2),再来讨论下次大值。

  • 如果次大值是r2r2r2,那么aaa和bbb的值都是r1+r2r1+r2r1+r2,两种策略需要的椅子数相同;
  • 如果次大值是l2l2l2,那么a=r1+l2a=r1+l2a=r1+l2,显然a>ba>ba>b,第二种策略最优;
  • 如果次大值是l1l1l1,那么b=r1+l1b=r1+l1b=r1+l1,显然a

注意上面的最优策略,第二种情况下,最优策略是最小的lll与最小的rrr配对;第二种情况下,最优策略是最大的lll与最大的rrr配对,可以得出最优策略就是小的lll与小的rrr配对,大的lll与大的rrr配对。

所以本题的最优策略也就是:将lll集合和rrr集合分别排序,排好序的lll和rrr依次配对。如果配对的lll和rrr来自同一个客人,就让他独坐一桌,否则,让配对的lll坐在rrr的右边。

所以本题贪心的过程可以总结为,从单个最优策略每个rrr选择与之最接近的lll,到局部最优策略按相对顺序配对。每个配对的lll和rrr表示需要多加max(l,r)max(l,r)max(l,r)张椅子,最后再加上这nnn个人自己坐的椅子就是本题的解了。

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N = 10005;
int l[N],r[N];
int main() {int n;std::cin>>n;for(int i = 0; i < n; i++) cin>>l[i]>>r[i];sort(l,l+n);sort(r,r+n);long long res = 0;for(int i = 0; i < n; i++) res += max(l[i],r[i]) + 1;std::cout<

相关内容