2024CSP-J2模拟赛2 补题报告

2024.10.4

江守栋

S07246


目录

· 比赛概况

· 比赛过程

· 题目分析

T1 【下棋(chess)】

1、题目大意

2、赛时思路

3、赛时代码&AC代码

T2 【汪洋(BigWater)】

1、题目大意

2、赛时思路

3、赛时代码&AC代码

T3 【删数(delnum)】

1、题目大意

2、赛时思路

3、赛时代码&AC代码

T4 【平分糖果(candy)】

1、题目大意

2、赛时思路

3、解题思路

4、AC代码

· 赛后总结


· 比赛概况

T1T2T3T4
AC0ptsAC70pts

前三题都能A的,但是T2关了输入输出流同步,再加上文件输入输出,输出出现了一些奇奇怪怪的错误 ,爆零

370pts --->270pts


· 比赛过程

T1 依旧很水 ,5min 秒掉

T2 一眼看上去像是 DP 或 dfs ,找到规律后发现可以直接用二位前缀和写 ,但是自己造了大样例后发现时间在 1s 上下飘忽不定 ,保险起见关了输入输出流同步 ,缺乏经验爆零两行泪

T3 一开始写了个模拟 ,后来找了找规律 ,但是调了很久都与答案差一点 ,于是就非常玄学地改了一些变量想拿部分分 ,结果 AC 了

T4 看上去像是背包 ,没时间写了 ,也没心态写了 ,直接采用六层循环暴力 ,结果数据真的水 ,暴力能拿 70 分


· 题目分析

T1 【下棋(chess)】

1、题目大意

有 n 个玩家 ,每个玩家有若干个 1 、2 、3 星英雄 ,一个 3 星英雄可以由 3 个 2 星英雄合成 ,一个 2 星英雄可以由 3 个 1 星英雄合成 ,记该玩家拥有 12 、3  星英雄的数量分别为 xy 、z则该玩家的战力为 18x+3y+z ,根据玩家战力从大到小排序 ,战力相同按序号从小到大排序

2、赛时思路

让 x 的数量尽量多 ,排个序就行

3、赛时代码&AC代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
	ll data,id;
}a[100005];
bool cmp(node x, node y){
	if(x.data==y.data) return x.id<y.id;
	return x.data>y.data;
}
int n;
ll x,y,z;
int main() {
//	freopen("chess.in","r",stdin);
//	freopen("chess.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>z>>y>>x;
		y+=z/3;
		z%=3;
		x+=y/3;
		y%=3;
		a[i].id=i;
		a[i].data=18*x+3*y+z;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++) cout<<a[i].id<<' '; 
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

T2 【汪洋(BigWater)】

1、题目大意

n*n的地图中 ,每个格子都有值 ,这些值有正有负 ,主角的初始值是100,第一步从 (1,1)  向右走到 (1,2)  ,以后每次行进有两种选择:1.按照上一次的方向继续走  2.顺时针旋转 90° 

(1,1) 走若干格子后回到 (1,1)  ,期间走过的格子不能再走 ,一个格子中不能连续旋转 ,问走完地图后主角得到的最大值是多少

2、赛时思路

本来想写dpdfs,分析后发现走过的格子一定是一个矩形的四条边 ,最大值即为这四条边的值的和+初始值100 ,既然有多次求和的过程 ,即可用前缀和优化 ,考虑到地图是一个二维的平面 ,所以可以直接写一个二维前缀和

ps:造出来大样例后关闭了输入输出流 ,老师说因为关闭了输入输出流 ,又没有写 endl ,所以我的输出就会保留在缓冲区里 ,导致判题机读不到数据 ,从而爆零

3、赛时代码&AC代码

#include<bits/stdc++.h>
using namespace std;
long long n,a[1005][1005],maxx=-0x3f3f3f3f;
long long sum[1005][1005];
int main() {
	freopen("BigWater.in","r",stdin);
	freopen("BigWater.out","w",stdout);
	std::ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>a[i][j];
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];
		
	
	for(int i=2;i<=n;i++){
		for(int j=2;j<=n;j++){
			maxx=max(maxx,sum[1][j]+(sum[i][j]-sum[i][j-1]-a[1][j])+(sum[i][j]-sum[i-1][j]-a[i][j])+(sum[i][1]-a[i][1]));
		}
	}
	cout<<maxx+100;
	fclose(stdin);	
	fclose(stdout);
	return 0;
}

T3 【删数(delnum)】

1、题目大意

有一个由正整数从小到大组成的数列 ,还有一个长度为 n 的数组 a 

每次操作时 ,将数列中第 a[1] 、a[2]  、……  a[n] 小的数同时移除

有 q 次询问 ,每次询问输出需要多少次操作才能将 x 移除 ,如果不可能移除 x ,则输出 0

2、赛时思路

对于任何一个 x ,如果 a_{i} < x ,那么可以把 x 前的 i 个数移除 ,x 相对于数列的位置也会变化

当 a_{i}== x 时 ,x 也就在这时被删掉了

3、赛时代码&AC代码

#include<bits/stdc++.h>
using namespace std;
int n,a[100005],q,x;
int ans=0;
bool flag=0;
int main() {
    freopen("delnum.in","r",stdin);
    freopen("delnum.out","w",stdout);
    cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	cin>>q;
	while(q--){
		ans=flag=0;
		cin>>x;
		for(int i=n;i>=1;i--){
			if(x>a[i]){
				//ans+=x/i;
				//x=x%i;
				ans=ans+(x-a[i])/i;
				x=a[i]+(x-a[i])%i;
				/*
				if(x==0||x==a[i]){
					flag=1;
					break;
				}
				*/
				if(a[i]<x){
					x-=i;
					ans++;
				}
			}
			if(a[i]==x){
				flag=1;
				ans++;
				break;
			}
		} 
		if(flag) cout<<ans<<'\n';
		else cout<<0<<'\n'; 
	}
//	fclose(stdin);
//    fclose(stdout);
	return 0;
}

T4 【平分糖果(candy)】

1、题目大意

小可有美味程度分别为 1~6 的糖果

美味程度为 i 的糖果有 a_{i} 个

问小可能不能把糖果平分成美味程度之和相同的两部分

2、赛时思路

没有思路 ,六层循环暴力找答案 ,没想到居然能拿 70pts

3、解题思路

考虑动态规划 ,这道题其实就是一个多重背包 ,明确了思路之后代码非常好写

4、AC代码

#include<bits/stdc++.h>
using namespace std;
int sum;
bool dp[10][10000];
int a[10];
int cnt=0;
bool flag;
int main(){
	while(1){
		cnt++;
		memset(dp,0,sizeof dp);
		dp[0][0]=1;
		flag=0;
		sum=0;
		for(int i=1;i<=6;i++){
			cin>>a[i];
			if(a[i]!=0) flag=1;
			sum+=a[i]*i;
		}
		if(flag==0)break;
		cout<<"Collection #"<<cnt<<":\n";
		if(sum%2){
			cout<<"Can't be divided."<<"\n\n";
			continue; 
		}
		sum/=2;
		for(int i=1;i<=6;i++){
			for(int j=0;j<=sum;j++){
				for(int k=0;k<=a[i];k++){
					if(j<k*i){
					    break;
					}
					dp[i][j]|=dp[i-1][j-k*i];
				}
			}
		}
		if(dp[6][sum]){
			cout<<"Can be divided.\n\n";
		}
		else{
			cout<<"Can't be divided."<<"\n\n";
		}
	}
	return 0;
}

· 赛后总结

今天总体来说还可以 ,可惜的是没遇到过在文件读写情况下关闭输入输出同步的情况 ,如果关闭了,就应该在输入后加上 endl ,或者压根不关闭 ,用 scanfprintf 

T3 本来没有清晰的思路 ,但是手推样例后找到了做法 ,以后如果有题没有思路 ,手推样例就好

T4 应该多想一想,转化成多重背包后就很好解了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值