日期:2023年10月1日星期日
学号:S07731
姓名:魏仲毅
1.比赛概况:
比赛总分共4题,满分400。
赛时拿到140分,其中第一题80分,第二题40分,第三题20分,第四题0分。
2.比赛过程:
先想出第一题的思路,觉得第一题很简单,就把第一题写了(但是忘记了数据大小,超时了一点)。
第二题卡了半天,想出来用桶做,但只测试了样例和两组小数据,没有考虑到大数据的情况。
第三题直接遍历了一遍P前边和P后面,找出不上升和不下降的,再判断一下P,就结束了。(样例都过了)
第四题直接疯狂摆烂(其实是没时间了),直接写了一个0(也不知道是怎么拿到10分的),但忘把freopen解注释了。
3.题解报告:
(1) 第一题:数字降级(down)
重点: 唯一分解定理。
情况:赛中80分,已补题。
题意:数字每一次降级都表示将一个数字除以一次它的任意一个因子,最少几次操作可以将一个数字n降级成一个质数。
赛时本题做题想法:想到是质数就为0,不是就为1,但没有优化。
题解:质数就是质数,需要0次;合数因为可以分解为若干个质数之积,只需要1次。
AC 代码:
#include<iostream>
using namespace std;
int main(){
long long n;
cin>>n;
for(int i=2;i<=n/i;i++){
if(n%i==0){
cout<<1;
return 0;
}
}
return 0;
}
(2) 第二题:分组(group)
重点:桶。
情况:赛中40分,已补题。
题意:n位玩家,分若干个小组。小组分数为小组内每位玩家分数组成的集合中没有出现过的最小的自然数,求总小组分数。
赛时本题做题想法:与正解有偏差,想到用桶做,但是把每个小组减去,计数器加分。
题解:用桶计数,一切以0为起始,0有几个,就至少有几分,再向上推进,计数器加分。
AC 代码:
#include<iostream>
using namespace std;
int t[1005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
int t1;
cin>>t1;
t[t1]++;
}
int minn=t[0],cnt=minn;
for(int i=1;i<=1000;i++){
minn=min(minn,t[i]);
cnt+=minn;
}
cout<<cnt;
return 0;
}
(3) 第三题:抢夺地盘(seize)
重点:最长子序列和(dp)。
情况:赛中20分。
题意:p为钱数最多,然后从1到p的钱数排布是从小到大的,从p到n的钱数排布是从大到小的。
需要改动最少的战力,使1到p的战力排布是从小到大的,从p到n的战力排布是从大到小的,求最少的变动次数。
赛时本题做题想法:遍历了一遍1到p和p到n,找出不上升和不下降的,多判断一下p。
题解:找到1到p的最长不下降子序列,再找到p到n的最长上升子序列,特判一下p。
AC 代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int INF=0x3f3f3f3f;
int a[N], b[N], c[N];
int n, p, pos;
int main(){
cin >> n >> pos;
for(int i=1; i<=n; i++) cin >> a[i];
b[++p]=a[1];
for(int i=2; i<pos; i++){
if(a[i]>=b[p]){
b[++p]=a[i];
}
else{
int l = 1, r = p, mid = p >> 1;
while(l != r){
if(a[i] < b[mid]) r = mid;
else l = mid + 1;
mid = (l+r) >> 1;
}
b[l] = a[i];
}
}
if(a[pos]>=b[p]){
p++;
}
else{
a[pos]=INF;
}
int ans=pos-p;
p=1;
c[p]=a[pos];
for(int i=pos+1; i<=n; i++){
if(a[i]<=c[p]) c[++p]=a[i];
else{
int l=1,r=p,mid=p>>1;
while(l!=r){
if(a[i]>c[mid]) r = mid;
else l=mid+1;
mid=(l + r)>>1;
}
c[l]=a[i];
}
}
ans+=(n-pos+1)-p;
cout<<ans;
return 0;
}
(4) 第四题:闯关(berrier)
重点:贪心。
情况:赛中0分(以后一定要去注释)。
题意:A、B可以选择一次跃过最多m距离,但闯关神器,可以让m距离变成k(m<k)。
两人距离不超过q(k<q)时可以相互传递这个闯关神器。求A和B都到达终点(即第n个关卡),最少需要使用几次闯关神器。
赛时本题做题想法:没时间了(下次改正),就过了一个样例。
题解:应使用dp来做,也可以用贪心。贪心的思路是如果小可一定要传给达达,则小可最多能到达(达达现在能到达的最远距离+q);
由于我们每一次交换神器的时机均为对方需要时,且我们不得不给的情况,如果不给会使得对方无法到达到终点,所以该交换次数为最少次数。
AC 代码:
#include <iostream>
using namespace std;
const int N=1e3;
int n,m,k,q,f,La,Lb,ans;
int a[N+5],b[N+5];
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];
while(1){
if(!f){
while(b[Lb+1]-b[Lb]<=m&&Lb+1<=n) Lb++;
if(Lb==n) break;
while(a[La+1]-b[Lb]<=q&&La+1<=n) La++;
ans++;?
f=1;
if(La==n) break;
}
else{
while(a[La+1]-a[La]<=m&&La+1<=n) La++;
if(La==n) break;
while(b[Lb+1]-a[La]<=q&&Lb+1<=n) Lb++;
ans++;
f=0;
if(Lb==n) break;
}
}
cout<<ans;
return 0;
}
4. 赛后总结:
本次比赛出现了忘删注释(打脸),时间不够用的问题,以后需要合理规划时间,前两道题可以用时1.5小时,不要被一道题卡住太久(就像我今天的第二题)。
后两道题如果没有思路,不用非要全对,30,40也可以。
以后绝对不能忘删注释!!!