可达鸭 CSP-J复赛模拟1补题报告

本文概述了一位参赛者在CSP-J复赛中的经历,包括各题得分、比赛过程中的思路转变和题解,展示了AC代码示例。着重讨论了数字降级、分组、抢夺地盘和闯关等题目解法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CSP-J复赛模拟补题报告

日期:2023.10.1星期日

1.比赛分数:

共四题,满分400,比赛中拿到120分,第一题90分,后三题每题得10分

2.比赛过程:

第一题开始想循环求素数,比赛中后来发现可以一次分解,改上后得90分。

第二题开始就没想好怎么做,想把前四各样例直接做。

第三个没想到DP,直接循环比较的。

第四题双指针暴力,也有的没有做过,仅过了1个样例。

3.题解报告:

(1)第一题:数字降级

情况:赛中90分,已补题

题意:输入一个数字,将数字除以它的任意一个因数,求多少次才能变为一个素数

题解:唯一分解定理,大于2的任何一个合数都可以分解成若干

素数相乘(最后我循环中的控制没开longlong,扣了10分)

AC代码:

#include<bits/stdc++.h>
using namespace std;
long long n,cnt=0;
bool q(long long a){
	for(long long i=2;i*i<=n;i++){
		if(n%i==0){
			return false;
		}
	}
	return true;
}
int main()
{
	cin>>n;
	if(q(n)){
		cout<<0;
	} 
	else{
		cout<<1;
	}
	return 0;
}

(2)分组

情况:赛中10分,已补题

题意:把n个数分成多组,求每组中最小的自然数加起来最大的数值

赛时想法:没想到怎么做,直接照着前四个测试点的数据测试的,但是只拿到10分

题解:因为求的是分组后最小的自然数,直接用桶标记哪些有哪些没有,循环比较每次的最小值,将最小值累加,即为最终的最大值。

AC代码:

#include<iostream>
using namespace std;
int cnt[1005];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        cnt[x]++;
    }
    int now=cnt[0],ans=now;
    for(int i=1;i<=1000;i++){
        now=min(now, cnt[i]);
        ans+=now;
    }
    cout<<ans;
    return 0;
}

​(3)抢夺地盘

情况:赛中10分,已补题

题意:有n个城镇,实现前p个为不下降的序列,后面p到n为不上升的序列,需要多少次调换。

赛时想法:没想到这个是求最长不上升和不下降子序列的,没有用DP,直接循环比较。

题解:1~p个为求最长不下降子序列,p~n个为求最长不上升子序列,均用到DP,但数据过大,需要更加缩小时间。利用二分对每一个不下降或不上升进行存储,存储时进行比较,能使时间更优,也能增加可能性。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
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]=1e9+1;
    }
    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)闯关

情况:赛时拿到20分,已补题。

题意:小可和达达两人分别在两个跑道进行闯关,两个人不能串跑道,并且只能向前方进行闯关,不能后退,并且假设小可和达达闯的每个关卡都可以顺利通过。小可、达达可以选择一次跃过最多 m 距离继续向后闯关,不需要每个关卡都闯过去。由于小可和达达是组队参加,小可和达达有一个闯关神器,可以让 m 距离变成 k(m<k)。开始时神器在小可的手中,小可和达达虽然分别在两个跑道,但是可以在两人距离不超过 q (k<q)时相互传递这个闯关神器。请问小可和达达都到达终点(即第 n 个关卡),最少需要使用几次闯关神器。

赛事想法:想用双指针贪心,但是在判断过关和交换时代码并不清楚,仅过两个样例。

题解:

需要用到贪心的算法,将距离和神器的位置进行贪心,尽量保证到了最远的距离再传递,并且判断如果另一人没有拿神器可不可以过关,尽量对传递的次数降低。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
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]=1e9+1;
    }
    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;
}

四.赛事总结

本次比赛中进行文件储存的时候,没有再在中间套一层文件夹,导致报0,并且审题时没有想到其他做法。以后需要多审题,仔细检查文件。

### 关于CSP-J复赛模拟题第四套 #### 题目描述 根据已知的参考资料[^3],以下是关于 **CSP-J 复赛模拟题4** 的相关内容: --- #### 解析与代码实现 ##### 问题背景 该题目涉及字符串处理逻辑。具体来说,程序需要读取若干组输入数据,并判断每组数据是否满足特定条件。 ##### 条件说明 对于长度为5的字符串 `s`,需满足以下个条件才能计数增加: 1. 字符串中的第三个字符等于第五个字符 (`s[2] == s[4]`)。 2. 字符串中前四个字符互相同 (即 `s[0], s[1], s[2], s[3]` 均)。 ##### 实现思路 通过逐行读入字符串并逐一验证上述条件来统计符合条件的字符串数量。 ##### 参考代码 下面是基于 C++ 编写的解决方案: ```cpp #include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; // 输入测试用例的数量 int cnt = 0; // 记录符合条件的字符串数目 string s; while (n--) { // 循环处理每一组输入 cin >> s; int len = s.length(); if (len == 5 && s[2] == s[4]) { // 判断长度以及第三位和第五位相等 bool flag = true; // 检查前四位是否有重复字符 for (int i = 0; i < 4; ++i) { for (int j = i + 1; j < 4; ++j) { if (s[i] == s[j]) { flag = false; break; } } } if (flag) { cnt++; } } } cout << cnt; // 输出最终结果 return 0; } ``` 以上代码实现了对输入字符串的逐条检验,并统计出符合指定条件的字符串总数。 --- #### 总结 本题主要考察的是字符串的操作能力以及基本的循环控制结构应用。需要注意边界情况以及效率优化,在实际比赛中应尽量减少必要的计算开销。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值