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

CSP-J复赛模拟补题报告

2023.10.2星期one

目录

CSP-J复赛模拟补题报告

1.比赛分数

2:比赛过程

3:题解报告

(1)down数字降级

(2)分组group

(3)抢夺地盘

(4)闯关barrier

四.赛后总结


1.比赛分数

共四题,满分400,比赛中拿到220分

T1(down):90

T2(group):100

T3(seize):20

T4(barrier):10

2.比赛过程

T1想到了合数可以被分为一个质数乘其他自然数,所以只需要判断这个数是不是合数就可以做。

T2第一眼看出来不是一个考验算法知识的,就造了几组数据尝试寻找规律深知自己遇到算法就蒟蒻大概过了10分钟找到思路打码也没遇到什么问题。

T3一开始以为是排序然后看变化,但却发现是更改数据不是交换数据,最后发现时间不够了就直接暴力打的,结果赛后讲评一看才发现这道题好难♂。

T4本来以为不可能做出来就放弃了,先把样例1用更完整的情况骗了下分(就是谈论小可以及达达利亚可以直接过去的情况)为此看了一遍题感觉可以做,所以就浅浅打了打(甚至“==”打成了“=”)结果后面发现就是一个比较简单但是又很多种特殊情况需要讨论的贪心,但是还剩最后17分钟,等到收卷还剩下1种情况没有讨论。把freopen补上就交了最后发现题目理解有问题,他们是从0开始走不是第一个数,以及我中间的测试数据都没有删干净还是比较后悔的,但凡能多看看就能从10分到60分(后面将数组从0开始记并且多打上4行删掉2行就能60)

3.题解报告

(1)down数字降级

情况:赛中90,已补题

题意:输入一个数,将数除以它的任意一个因数,求除多少次能将其分解为一个质数

题解:判断质数,是0否1(唯一分解定理)

AC奉上:

#include<iostream>
using namespace std;
int main(){
//	freopen("down.in","r",stdin);
//	freopen("down.out","w",stdout);
	long long n;
	cin>>n;
	for(long long/*十年OI一场空,不开LL见祖宗*/ i=2;i*i<=n;i++){//不优化会爆,优化为1/2也会爆
		if(n%i==0&&i!=n){
			cout<<1;
			return 0;
		}
	}
	cout<<0;
//	fclose(stdin);
//	fclose(stdout);	
	return 0;
} 

(2)分组group

情况:赛中AC,赛后补了补锌Ⅳ🦌

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

题解:桶标记完后while循环找0找到零就把前面所有的串结算一下外面再套个while没有0时结束并累加里面while的值。

介个是AC代码:

#include<iostream>
using namespace std;
int main(){
//	freopen("group.in","r",stdin);
//	freopen("group.out","w",stdout);
	int n,a[1005]={0},x,sum=0,min=100005,ret=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x;
		a[x]++;
	}
	while(a[0]!=0){
		sum=0;
		min=100005;
		while(a[sum]!=0){
			if(a[sum]<=min){
				min=a[sum];
			}
			sum++; 
		}
		ret+=sum*min;
		for(int i=0;i<=sum;i++){
			a[i]=a[i]-min;
		}
	}
	cout<<ret;
//	fclose(stdin);
//	fclose(stdout);	
	return 0;
}

(3)抢夺地盘

情况:赛中暴力20,已补题

题意:有n个城镇代表的钱,实现前p个为不下降的序列,后面p到n为不上升的序列,求实际与序列差多少个。

题解:分别求两个不同方向的最长上升子序列(1~p-1;p+1~n),比较长度上的不同并输出。dp时复为n²,通过2分优化为nlog(n)

想了好久QWQ:

#include<iostream>
using namespace std;
int main(){
	int a[100005]={0},lis[100005]={0},sum=1,ans=0,n,p;
	cin>>n>>p;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	lis[1]=a[1];
	for(int i=2;i<p;i++){
		if(a[i]>=lis[sum]){
			lis[sum++]=a[i];
		}
		else{
			int L=1,r=sum,mid=sum>>1;
			while(L!=r){
				if(a[i]<lis[mid]){
					r=mid;
				}
				else L=mid+1;
				mid=(L+r)>>1;
			}
			lis[L]=a[i];
		}
	}
	if(a[p]>=lis[sum]){
		sum++;
	}
	else{
		a[p]=1145141919810;
	}
	ans+=p-sum;//上半
	sum=1;
	lis[1]=a[p];
	for(int i=p+1;i<=n;i++){
		if(a[i]<=lis[sum]){
			lis[sum++]=a[i];
		}
		else{
			int L=1,r=sum,mid=sum>>1;
			while(L!=r){
				if(a[i]>lis[mid]){
					r=mid;
				}
				else{
					L=mid+1;
				} 
				mid=(L+r)>>1;
			}
			lis[L]=a[i];
		}
	} 
	ans+=(n-p+1)-sum;
	cout<<ans<<endl;
	return 0;
} 

(4)闯关barrier

情况:赛时10分,未补题

题意:两个人可以使用一个使跨度变大k-m的神器,但是因为只有一个所以需要来回使用,传的距离不超过q。问需要传多少次。

题解:大模拟,将几种特殊情况列出来解决。需要贪心思路。

60分代码(赛后)

#include<iostream>
using namespace std;
int main(){
//	freopen("barrier.in","r",stdin);
//	freopen("barrier.out","w",stdout);
	int n,m,k,p,a[1005]={0},b[1005]={0},sum1=0,sum2=0,flag1=0,flag2=0,bang=0,ans=0;
	cin>>n>>m>>k>>p;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(i!=1){
			if(a[i]-a[i-1]>sum1){
				sum1=a[i]-a[i-1];
			}
		}
	}
	for(int i=1;i<=n;i++){
		cin>>b[i];
		if(i!=1){
			if(b[i]-b[i-1]>sum2){
				sum2=b[i]-b[i-1];
			}
		}
	}
	if(sum1<=m||sum2<=m){	
		if(sum2<=m){
			cout<<0;
			return 0;
		}
		if(sum1<=m){
			cout<<1;
			return 0;
		}
	}
	while(flag1!=n||flag2!=n){
		if((flag1==n&&bang==1)||(flag2==n&&bang==0)){
			cout<<ans;
			return 0;
		}
		if(bang==0){
			while(a[flag1+1]-b[flag2]<=p&&flag1!=n){
				flag1++;
			}
		}
		else{
			while(b[flag2+1]-a[flag1]<=p&&flag2!=n){
				flag2++;
			}
		}
		ans++;
		if(bang==0){
			bang=1;
		}
		else{
			bang=0;
		}
	}
	cout<<ans;
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}


四.赛后总结

第一题出现小错误没有AC,时间安排不当导致没有做完,比较可惜的。。。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值