CSP复赛模拟赛2后补题报告

日期:2023年10月2日星期一
  学号:S14029
  姓名:黄子航
    1. 比赛概况:
  比赛总分共 4 题,满分 400,赛时拿到60 分,其中第一题 30 分,第二题  0 分,第三题 20 分,第
四题 10 分。
    2. 比赛过程:
  比赛时按照顺序做的,第一题一开始是暴力求解,优化也做得不错,但是漏了一种可能,所以分很低,
    3. 题解报告:
    (1) 第一题:人员借调
  情况:赛中30分,已补题。
  题意:一人在A地工作中非常出色,B地领导想让他帮忙处理一些工作,但由于此人工作出众,如果他连
续呆在B地大于等于240分钟时,回来后就会强制留在A地7天(10080分钟),来回AB地也需要400分钟,问
此人最少多少分钟完成所有工作项目?
  赛时本题做题想法:暴力解题,但没有想到可以把所有任务都做完在回去。
  题解:分情况讨论+优化
  AC 代码:

#include<bits/stdc++.h>
using namespace std;
int a[1005],n,x,ans=400,sum,cnt;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x;
		sum+=x;
		ans+=x;
		if(sum>=240){	
			cnt++;
			sum=x;
		}	
	}
	if(cnt>=1){
		if(n==1)	
			ans+=10080;
		else 
			ans=min(ans+10080,ans+cnt*400); 
	}
	cout<<ans;
	return 0;
}

(2) 第二题:计算
  情况:赛中0分,已补题。
  题意:使用n,m,k算出x的数值,1、n<=x<=m。2、x十进制各位上的和等于k。如果x有多个,输出
各位数乘积最大的一个,如果乘积也相等,则输出x最小的一个。
  赛时本题做题想法:思路有很多,但是都编不出来,只好输出了题例。
  题解:简简单单的枚举法,然后优化。
  AC 代码:

#include<bits/stdc++.h>
using namespace std;
int e[5000005],p[5000005];
int main(){
    //freopen("calc.in","r",stdin);
    //freopen("calc.out","w",stdout);
    p[0]=1;
    for(int i=1;i<=5000000;i++){
        e[i]=e[i/10]+(i%10);
        p[i]=p[i/10]*(i%10);
    }
    p[0]=-1;
    int t;
    cin>>t;
    while(t--){
        int m,n,k,ans=0;
        cin>>m>>n>>k;
        for(int i= m;i<= n;i++){
            if (e[i]==k&&p[i]>p[ans]){
                ans=i;
            }
        }
        cout<<ans<<" "<<p[ans];
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

(3) 第三题:智能公交
  情况:赛中20分,已补题。
  题意:马路上有n个公交车站,编号从1~n,每两个站都相隔1千米,有一辆智能公交车,
无人时停在x站,有人呼叫公交车时,公交车会很快开到那一站,接乘客上车,到达后让
乘客下车,再返回x站。请问x站在哪里时,公交车跑的路程最少?若最少的有多个,输出
编号靠前的站台。
  赛时本题做题想法:暴力枚举法,计算每个车站作为x站时需要开的路程,再进行比较,
输出路程最短的。
  题解:本题应该使用贪心算法,通过计算可以发现,x站在起点终点之间时,所需的路
程为2|起点-终点|,在起点终点之外时,所需的路程就是2|离x较远的点-x|,后者肯定是
大于前者的。由此可知,本题中贪心算法表现为尽量多的占据起点和终点之间。

  AC 代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m,a,b;
    long long ans=1e18,pos,sum=0;
    cin>>n>>m;
    vector<long long> p(n+2),s(n+2),p1(n+2),s1(n+2);
    while(m--){
        cin>>a>>b;
        p[a-1]+=2;
        s[b+1]+=2;
        sum+=(b-a)*2;
    }
    for(int i=n;i>=1;i--){
        p[i]+=p[i+1];
        p1[i]=p1[i+1]+p[i];
    }
    for(int i=1;i<=n;i++){
        s[i]+=s[i-1];
        s1[i]+=s1[i-1]+s[i];
        if(s1[i]+p1[i]<ans){
            pos=i;
            ans=s1[i]+p1[i];
        }
    }
    cout<<pos<<" "<<ans+sum<<endl;
    return 0;
}

(4) 第四题:异或和
情况:赛中10分,已补题。
题意:多个集合中有n个数字,
在一个集合中选择一个数字,收益就是这个数字,选择多个
数字,收益是这些数字的异或和,最多选取m个数字,问每个集合的收益和最大位多少。
赛时本题做题想法:暴力枚举法,并且只写了一半,感觉没法写,直接开摆。
题解:使用dp算法,通过二维数组优化来解决空间问题,最后在进行枚举选出最大。
AC 代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,dp[2005][2050],num[2005][2005],dpp[2050],zz[2005];
vector<int> ve[2005];
int main(){
	cin>>n>>m;
	for (int i=1;i<=n;i++){
		int x,y;
		cin>>x>>y;
		ve[y].push_back(x);
		zz[y]++;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=2047;j++){
			dp[i][j]=1e9;
		}
	}
	for(int zu=1;zu<=2000;zu++){
		if (zz[zu]!=0)	
			dp[1][ve[zu][0]]=1; 
			  
		for(int i=2;i<=zz[zu];i++){
			dp[i][ve[zu][i-1]]=1; 
			for(int j=1;j<=2047;j++){
				if(dp[i-1][j]!=1e9){
					dp[i][j]=min(dp[i][j],dp[i-1][j]);
					dp[i][j^ve[zu][i-1]]=min(dp[i-1][j]+1,dp[i][j^ve[zu][i-1]]);
				}
			}
		}
		for(int j=1;j<=2047;j++){
			if(dp[zz[zu]][j]!=1e9)
				num[zu][dp[zz[zu]][j]]=j;
		}
		for(int i=1;i<=zz[zu];i++){
			for(int j=1;j<=2047;j++){
				dp[i][j]=1e9;
			}
		}
	}
	for(int i=1;i<=2000;i++){
		for(int j=m;j>= 1;j--){
			for(int k=1;k<=zz[i];k++){
				if(j>=k)
					dpp[j]=max(dpp[j],dpp[j-k]+num[i][k]);
			}
		}
	}
	cout<<dpp[m];
	return 0;
}

4. 赛后总结:
本次模拟赛由于知识不够充分,编程能力较弱的原因导致分数低,我应该多做练习,了解新
的知识,加强编程能力,从而使下次避免出现此类的错误。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值