CSP-J模拟赛二(补题)

日期:2023.10.2

学号:s07661        

一.比赛概况:

总分400分,拿到140分,其中第1题20分,2题70分,3题50分,4题0分,

二. 比赛过程

第一题模拟,做了个50分,第二题用sort,本身思路也知道超时,70不错了,第三题枚举20分错了,第四题就是不会做

三. 解题报告

一.人员借调

1.题目大意

B 地的领导想借调小可帮忙处理 件事情,小可处理第 件的耗时为分钟。如果小可在 B 地待连续大于等于240分钟时,A 地领导会非常的不高兴,将强制把小可留在 A 地 天( 分钟), 天结束后小可可以继续留在 A 地正常工作或者继续前往B 地帮忙处理事情。
于是,小可有了一个对策,在 分钟快到的时候就此 B 地回到 A 地,然后再去 B 地,这样的话
分钟就会重新计时。注意:从 A 地往返一次 B 地会耗时 分钟(这个时间不计算到待在 B 地的时间)。注:这个事情必须处理完才可以继续后面的内容

2.比赛中的思考

我一步一步模拟,一步一步递推,试了很多样例,问题都不大,想着一步一步加,然后判断是否超过240,加上下个数是否大于240,进行操作。

3.解题思路

用累加器判断什么时候要回去,把这些数都累加上,最后判断有无超过240的,如果有,输出结果加10480。

4 .AC代码

#include<bits/stdc++.h>
using namespace std;
long long n,a[1005],num[1000005];
int main(){
	long long sum=0,sum1=10480,sum2=400,maxn=0,t=0;
	cin>>n;
	for(long long i=1;i<=n;i++){
		cin>>a[i];//任务
		sum1+=a[i];//累加
		maxn=max(maxn,a[i]);//找最大值
	}
	for(long long i=1;i<=n;i++){
		if(t+a[i]>=240){//什么时候回去
			sum2+=400+a[i];
			t=a[i];
		}else{
			t+=a[i];
			sum2+=a[i];
		}
	}
	if(maxn>=240){//有无超过240的
		cout<<sum1<<"\n";
	}
	else{
		cout<<min(sum1,sum2)<<"\n";
	}
	return 0;
} 

二.计算

1.题目大意

计算需要使用到三个整数 m,n,k

计算条件如下(设 x 为满足计算条件的数字):1:m≤x≤n 2:x 在十进制下所有位上的数字之和为 k  根据计算条件得到的 x 可能会很多,请输出十进制下所有位上的数字的积最大的那个

2.比赛中的思考

暴力枚举,会超时

3.解题思路

打表,节省时间

4 .AC代码

#include<bits/stdc++.h>
using namespace std;
int t;
int m,n,k,cnt;
struct node{
	int dc,c;
}a[5000005];

int main(){
	
    for(int i=1;i<=5000005;i++){//循环打表 
    	int t=i,sum=0,sum1=1;
		while(t>0){
			sum+=t%10;//数位和 
			sum1*=t%10;//数位积 
			t/=10;
		}
		a[i].dc=sum;//打表数组 
		a[i].c=sum1;
	}
	cin>>t;
	
	for(int i=1;i<=t;i++){
		int maxn=-1e9,id;
		cin>>m>>n>>k;//输入 
		for(int j=m;j<=n;j++){
			if(a[j].dc==k&&maxn<a[j].c){//判断求最大 
				maxn=a[j].c;
				id=j;
			}
		}
		
		cout<<id<<" "<<maxn<<"\n";//输出 
	}
	
	return 0;
} 

三.智能公交

1.题目大意

现在有 m 个人要依次乘坐智能公交,每个人都会等待智能公交停在 x 站台之后在按动当前站台按钮准备乘坐公交。现在已知第 i 个人都是从 a 站台到 b 站台。请你计算 x ,使得智能公交移动距离最短。最终输出 x 和最短的距离,x 若有多个,输出最小的一个。

2.比赛中的思考

暴力,没什么可说的,就是写的有些问题,本来也没想AC。

3.解题思路

因为要考虑x到两个点的距离和,

把输入的两个数组合并,就是D4货仓选址的题。

4 .AC代码

​
#include<bits/stdc++.h>
using namespace std;
int n,m;
bool flag;
int main(){
	long long a[1000005],b[1000005],c[2000005],cnt=0,minn=1e9,maxn=-1e9,sum=0;
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i]>>b[i];
		c[++cnt]=a[i];//合并 
		c[++cnt]=b[i];
		sum+=(b[i]-a[i]);
	}
	sort(c+1,c+m+m+1);//排序 
	int zhan=c[m]; 
	for(int i=1;i<=2*m;i++){
		sum+=abs(zhan-c[i]);//货舱选址操作 
	}
	cout<<zhan<<" "<<sum;//输出公交停靠的位置和最短距离 
	return 0;
} 

​

四.异或和

1.题目大意

多个集合中总共有 n 个数字,并且已知每个数字的大小 a​i​​ 和属于某个集合 b​i​​。

在一个集合中选择一个数字,收益为这个数字的大小,选择多个数字,收益为这些数字的异或和。

总收益为每个集合的收益之和。注意:最多从中选择 m(m≤n) 个数字,使这些数字总收益最大。

2.比赛中的思考

收到这道题的时候,大脑直接宕机了,也没剩多长时间,随便蒙了个代码就交了

3.解题思路

先处理每组数据,再处理dp数组, 在构成j所需的个数 最后枚举n组,用分组背包解决这道题,输出dp2[m];

4 .代码

补题时,先做了两个十分的

#include<iostream>
#include<cstring>
#define INF 0x3f3f3f3f
#define ll long long
#define N 1000005
#define M 100005
using namespace std;
int dp[2005][2050]={0};
int main(){
	int n,m,a[2005];
	cin>>n>>m;
	for(int i=1; i<=n; i++){
		int x;
		cin>>a[i]>>x;//输入 
		dp[1][a[i]] = 1;
	}
	for(int i=2; i<=n; i++){
		for(int j=1; j<=2047; j++){
			if(dp[i-1][j]){//如果前i-1个数能够构造j 
				dp[i][j] = 1;
				dp[i][j^a[i]] = 1;//状态转移 
			}
		}
	}
	for(int i=2047; i>=1; i--){
		if(dp[n][i]){
			cout<<i;//输出 
			break;
		}
	}
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n,m,maxn,dp[2505][2505]={0},a[2505];
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int x;
		cin>>a[i]>>x;//输入 
		dp[1][a[i]]=x;//判边界 
	}
	for(int i=2;i<=n;i++){
		for(int j=1;j<=2047;j++){
			dp[i][j]=min(dp[i][j],dp[i-1][j]);//状态转移 
			dp[i][j^a[i]]=min(dp[i][j^a[i]],dp[i-1][j]+1);
		}
	}
	int maxx=0;
	for(int i=1;i<=10;i++){
		if(dp[n][i]<=m){
			maxx=max(i,maxx);//判最大 
		}
	}
	cout<<maxx;//输出最大值 
	return 0;
} 

然后是AC代码

#include<bits/stdc++.h>
using namespace std;
int n,m,maxn,dp[2505][2505]={0},a[2505][2505],cnt[2505],num[2505][2047]={0};
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int x,y;
		cin>>x>>y;//输入 
		cnt[y]++;
		a[y][cnt[y]]=x;
	}
	for(int zu=1;zu<=2000;zu++){//处理每组 
		if(cnt[zu]==0)continue;
		memset(dp,0x3f,sizeof dp);
		for(int i=1;i<=cnt[zu];i++){
			dp[i][a[zu][i]]=1;//前i个数构成a[zu][i]一定只需要一个数本身 
		}
		//处理dp数组
		int x=0x3f3f3f3f;
		for(int i=2;i<=cnt[zu];i++){
			for(int j=1;j<=2047;j++){
				if(dp[i-1][j]!=x){
					dp[i][j]=min(dp[i][j],dp[i-1][j]);
					dp[i][j^a[zu][i]]=min(dp[i][j^a[zu][i]],dp[i-1][j]+1);//状态转移 
				}
			}
		}
		for(int j=1;j<=2047;j++){
			if(dp[cnt[zu]][j]!=x){
				int k=dp[cnt[zu]][j];//构成j所需的个数 
				num[zu][k]=max(num[zu][k],j);
			}
		}
	}
	int dp2[2005]={0};
	for(int i=1;i<=2000;i++){//枚举n组 
		for(int j=m;j>=1;j--){//背包容量 
			for(int k=1;k<=cnt[i];k++){//枚举放几个数据进去 
				if(j>=k){
					dp2[j]=max(dp2[j],dp2[j-k]+num[i][k]);
				}
			}
		}
	}
	cout<<dp2[m]; 
	return 0;
} 

总结:今天比昨天有进步,在题更难的情况下,分比昨天还高,也适应了现在的考试机制,明天继续加油,在进步一点点,争取省一!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值