日期:2023.10.1
学号:s07661
一.比赛概况:
总分400分,拿到80分,其中第1题80分,2题0分,3题0分,4题0分,
赛后补题:全部正确
二. 比赛过程
第一题想了想,做了个80分,第二题用较长的时间想思路,不太清楚解法,半蒙半做写的,第三题方法不对错了,第四题想着拿几十分,结果中间错了,也没拿分
三. 解题报告
一.数字降级
1.题目大意
问最少几次操作可以将一个数字 n ,降级成一个质数?
2.比赛中的思考
一开始想多了还用欧拉筛,后来想了想用判断质数就行,然后没考虑到n最大10^10这事,用的int然后两个测试点超限然后……炸了
3.解题思路
考虑到唯一分解定理,输出非1即0,就是质数判断,如果他是质数,输出0,如果他不是质数,输出1.
4 .AC代码
#include<bits/stdc++.h>
using namespace std;
long long n;
bool p(long long n){
if(n<2)return 0;
for(long long i=2;i*i<=n;i++){
if(n%i==0)return 0;
}
return 1;
}
int main(){
cin>>n;
if(p(n)){
cout<<0;
}
else cout<<1;
return 0;
}
二.分组
1.题目大意
总共召集了 n 位玩家,每位玩家有一个专属分数 ai,现在需要将 n 为玩家进行分组,分组之后每个组将获得一个小组专属分数 bi。小组专属分数为小组内每位玩家专属分数组成的集合中没有出现过的最小的自然数。比如第一组中每个人分数为1,2
,那么小组分数为0
,第二组中每个人的分数为0,1,2
,那么小组分数为3
。为了提高胜率,肯定要让 ∑bi 最大,请输出最大的 ∑bi 。
2.比赛中的思考
刚拿到手时是有点懵的,不太会,用较长的一段时间想思路,不太清楚正确解法,只确定要用桶存储,半蒙半做写的
3.解题思路
用桶存储,0的数量次循环遍历桶,桶中元素数-1,找到空位置,sum累加,break最后两层循环结束输出sum
4 .AC代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005],b[100005];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[a[i]]++;
}
int temp=b[0],sum=0;
for(int i=1;i<=temp;i++){
for(int j=1;j<=1001;j++){
if(b[j]==0){
sum+=j;
break;
}
else b[j]--;
}
}
cout<<sum;
return 0;
}
三.抢夺地盘
1.题目大意
小可在游戏中为了防止被其他玩家抢走城镇,在排兵布阵的过程中将钱数最多的城镇放在了 p 位置,然后从 1 到 p 的钱数排布是从小到大的,从 p 到 n 的钱数排布是从大到小的。这时出现了一个问题,如果某一个城镇 a 由于钱的原因比另一个城镇 b 更靠边(距离 p 位置更远),但是战斗力 a 比 b 更大,两个城镇会爆发矛盾。如果内部发生矛盾,会影响小可的整体安排。小可现在可以通过调整城镇人数的方式更改城镇的战斗力,但是为了稳定性考虑,被更改的城镇越少越好,请问小可最少调整几个城镇可以满足要求?
2.比赛中的思考
比赛中题目理解了,但我思路是有问题的,我想的是把从1~p这部分先从小到大排序,再把p到n这部分从大到小排序,和原先输入的进行对比看有几处不同,这种方法是行不通的
3.解题思路
线性DP,前面最长不下降子序列,后面最长不上升子序列(单层循环时间复杂度O(n)级别优化)用sum统计
4 .AC代码
#include<bits/stdc++.h>
using namespace std;
int n,p;
int a[100005];
int main(){
cin>>n>>p;
int maxn=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(i<=p)maxn=max(maxn,a[i]);
}
int sum=0;
int cnt=0,dp[100005];
for(int i=1;i<=p;i++){
if(dp[cnt]<=a[i]){
dp[++cnt]=a[i];
}
else{
int index=upper_bound(dp+1,dp+cnt+1,a[i])-dp;
dp[index]=a[i];
}
}
sum+=p-cnt;
int cnt1=0,dp1[100005];
if(maxn!=a[p]){
a[p]=1e9;
p++;
}
for(int i=n;i>=p;i--){
if(dp1[cnt1]<=a[i]){
dp1[++cnt1]=a[i];
}
else{
int index=upper_bound(dp1+1,dp1+cnt1+1,a[i])-dp1;
dp1[index]=a[i];
}
}
sum+=(n-p+1)-cnt1;
cout<<sum;
return 0;
}
四.闯关
1.题目大意
小可、达达可以选择一次跃过最多 m 距离继续向后闯关,不需要每个关卡都闯过去。由于小可和达达是组队参加,组委会赠与了小可和达达一个闯关神器
,可以让 m 距离变成 k(m<k)。开始时神器在小可的手中,小可和达达虽然分别在两个跑道,但是可以在两人距离不超过 q (k<q)时相互传递这个闯关神器。请问小可和达达都到达终点(即第 n 个关卡),最少需要使用几次闯关神器
。
2.比赛中的思考
本来不会,思考了一会,居然!还是不会~。尝试拿部分分顺便整一下,样例是都对了,但为何爆零也是很疑惑??
3.解题思路
模拟,基本上模拟整个过程,先让两人能硬走就硬走 ,处理一下每个人可以跳跃的最大距离,然后用死循环让小可,或达达尽可能往后走
4.AC代码
#include<iostream>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1000005
#define M 100005
using namespace std;
int n,m,k,q,a[N],b[N],f=0;
int main() {
cin>>n>>m>>k>>q;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=n; i++) cin>>b[i];
int posa = 0,posb = 0,ans = 0;
//先让两人能硬走就硬走
//处理一下每个人可以跳跃的最大距离
while(1) {
int la,lb;
la = lb = m;
if(f == 0) la = k;
else lb = k;
//让小可,或达达尽可能往后走
for(int i=posa+1; i<=n; i++) {
if(a[i] - a[posa] <= la) {
posa = i;
} else {
break;
}
}
for(int i=posb+1; i<=n; i++) {
if(b[i] - b[posb] <= lb) {
posb = i;
} else {
break;
}
}
//判断此时posa和posb能否同时到达终点如果能,直接break
if(posa >= n && posb >= n) {
break;
} else {
//如果没有看看神器在谁手里,让它回到另一个人卡住的位置
if(posb < n) {
//达达卡住了
//在a数组中找到第一个离b最远但是能够传递神器的地方
int index = lower_bound(a+1,a+n+1,b[posb]+q) - a;
if(a[index]>b[posb]+q) index--;
ans++;
f = 1;
posa = index;
} else if(posa < n) {
//小可卡住了
//在b数组中找到第一个离a最远但是能够传递神器的地方
int index = lower_bound(b+1,b+n+1,a[posa] + q) - b;
if(b[index] > a[posa]+q) index--;
ans++;
f = 0;
posb = index;
}
}
}
cout<<ans;
return 0;
}
总结:
今天做的成绩差了点,但至少没有犯忘删freopen的注释,忘删exe文件这种低级错误,下次审题再细,不要犯粗心错,不要太倔,别最后画蛇添足。争取过复赛拿奖,让这文档有机会再用。要自信,加油。