CSP-X模拟赛2---- 补题报告

2023年10月13日

S*****6

总分数:(400/210)

T1【称心如意】:100

T2【AC万岁】:100

T3【解救达达】:10

T4【整理文本】:0

一.【题目总结】

T1:第一题还可以,就是在输出的时候纠结了一下,最后样例对了。

这个100分是待定(老师考的时候C++没关,考成了原来的。不过我重判对了,大家不要学我!!)

T2:这道题很简单,是4道题里面最简单的一道,轻轻松松~~

T3:第三题看起来很好算,但是没人教我二进制怎么转啊!!(抓狂)(发疯)(在地上阴暗扭曲的爬行)

T4:因为时间不够用了(被第三题折磨的),所以直接放弃~

二.【题目分析】
1.【称心如意】

题目:

一个正整数数字 N,要得到一个称心如意的序列 S 与之匹配,这个序列需要满足以下几个条件:

1、序列的长度为 N+1

2、假设序列第 i位取值为 j ( j的范围为 1 到 9),那么需要满足 N%j==0,并且需要满足 i能整除 N/j,即 i%(N/j)==0

3、满足条件2的基础上,j的取值应该尽量小

4、若条件2不能满足,那么第 i位输出一个 -

思路:

首先定义n,一个charl类型的a数组,输入n。

然后用两次for,外层循环n-1次,枚举i。内层循环1-9次,枚举j。我们要判断 j是否符合条件 2 的要求。可以定义一个flag数组判断。如果flag=1;那么已经找到了最小的j,输出j就行。反之输出"--"。最后内循环要加一个break结束。

AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	int N,s[1005];
	cin>>N;
	for(int i=0;i<=N;i++){
		int flag=0,p;
			for(int j=1;j<=9;j++){
				if(N%j==0){ 
		  int t=N/j;
			if(i%t==0){
			flag=1;
			p=j;
			break;  
			}
		}
    }
    if(flag==0){
    	cout<<"-";
	}
	else if(flag==1){
		cout<<p;
		
	}
}
	return 0;
     }
2.【AC万岁】

题目:

定一个字符串,请计算ac作为字符串子序列出现的次数

注意:字符串子序列指的是从最初字符串通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。例如,acfbdebcd都是abcdef的子序列,而cae并不是。

思路:

本人:打暴力(稍微优化),用两个for循环,第一个for循环0~len-1,判断'c'前面有多少个'a';第二个for循环i-1~len-1,计数器求出一共有多少字串。最后输出计数器。

AC代码:

#include<iostream>//时间法度O(n^)
#include<cstdio>
#include<string>
using namespace std;
int main(){
	string s;
	long long cnt=0;
	cin>>s;
	long long len=s.size();
	for(long long i=0;i<len;i++){
		if(s[i]=='a'){
			for(long long j=i+1;j<len;j++){
				if(s[j]=='c'){
					cnt++;
				}
			}
		}
	}
	cout<<cnt;
	return 0;
}

Teacher :

多定义一个t数组和累加器

一个for循环,for循环里面第一个if判断'a'后面有多少'c',找到一个计数器+1;第二个if判断'c'前有多少'a',将结果存到t数组里.第二个单层for循环判断字符串里的'c',找到了就累加t[i];最后输出累加器。

AC代码:

#include<iostream>//此方法时间法度O(n)
#include<cstdio>
#include<string>
using namespace std;
int main(){
	string s;
	int cnt=0,t[100005],sum=0;
	cin>>s;
	int len=s.size();
	for(int i=0;i<len;i++){
		if(s[i]=='a'){
			cnt++;
		}
		if(s[i]=='c'){
			t[i]=cnt;
		}
	}
	for(int i=0;i<len;i++){
		if(s[i]=='c'){
			sum=sum+t[i];
		}
	}
	cout<<sum;
	return 0;
}
3.【解救达达】

题目:

怪兽抓走了达达,小可想把达达救出来

怪兽的名字叫做 1,是因为怪兽最喜欢的数字就是1,而最害怕的数字就是0

怪兽每天以数字为食,而吃的数字是由二进制表示的。

现在小可知道只要有足够多的 0 混入怪兽的食物,就可以击败怪兽,救出达达。

而食物在被怪兽吃掉之前,会被检查,如果数字的二进制中有两个及以上的 0 (前导 0不算,即从第一个非0数表示二进制),怪兽不会吃掉这个数字。

小可给怪兽贡献了一个区间为 [a,b] 的数字,请计算一下这个区间内有多少个数字会伤害到怪兽

思路

本人:暴力枚举

(请忽略我丑陋的代码不准复制)

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
long long cnt=0;
int c(int a,int b){
	int t;
	long long cnt1=0,cnt2=0;
	while(t!=0){
		if(t%2==0){
		cnt++;
		}
		t=t/10;
		if(t%10==0){
			return 0;
			cnt1++;
		}
		else {
			return 1;
			cnt2++;
		}
	}
}
int main(){
	freopen("rescue.in","r",stdin);
	freopen("rescue.out","w",stdout);
	int a,b;
	cin>>a>>b;
    for(int i=a;i<=b;i++){
    if(c(a,b)==1){
    	cnt++;
	}
	}
	cout<<cnt<<" ";
	fclose(stdin);
	fclose(stdout);
	return 0;
}

Teacher :

      可以直接便利64位(long long的最大字符数)全1的二进制数,然后对每一个二进制表示为全一的数,减去2的j次方。
将它变成只有一个0的二进制的数,再判断这个数在不在a~b的区间里。如果在,计数器就+1;
最后输出计数器

AC代码(可以复制)

#include<iostream>
#include<cstdio>
#define ll long long;//简写long long头文件
using namespace std;
long long a,b;
int main(){
	cin>>a>>b;
	long long cnt=0;
	for(int i=1;i<=63;i++){//遍历所有1的位置
		for(int j=0;j<=i-2;j++){//遍历所有0的位置
			long long s=(1ll<<i)-1-(1ll<<j);//某一位为全1的个数-1
			if(s>=a&&s<=b){
				cnt++;
			}
		}
	}
	cout<<cnt;
	return 0;
     }
4【整理文本】

(本题较为复杂,后面有图画,样例辅助理解)

题目:

小可获得了一个新的任务,需要整理一份文本。

为了使得文本可以在一页之内就打印成功,小可必须使得文本整理在 M最后行之内。

小可数出了文本中总共有 N个单词,并且小可记录出来了每个单词的长度 L​i​​。

整理出来的文本必须要满足行首为当前行的第一个单词,相邻的两个单词需至少由一个空格间隔。

当所有文本按照要求整理结束之后,得到每一行的行宽(当前行中单词的 ∑L​i​​ 加 空格数量),请使得其中最大的行宽最小,请输出对应的行宽值。

注意:单词不能调换顺序,并且单词不能舍弃一部分。

思路:

先用自定义函数判断行数(当单词加空格正好是最大的行宽时,最后一个单词后不用添加空格;当单词加空格大于最大的行宽时,由于单词不能舍弃,就需要在这一行单词中删去最末尾的一个,转换到下一行)。再运用二分查找不断改变区间,找到mid。最后输出上下限的一个就可以了。

样例和解释:

 AC代码:

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
long long n,m,a[200005];
bool check(long long mid){
	long long cnt=1,sum=-1;
	for(long long i=1;i<=n;i++){
		if(sum+a[i]+1<=mid){
			sum+=a[i]+1;
		}
		else{
			cnt++;
			sum=a[i];
		}
	}
	return cnt<=m;
}
int main(){
	cin>>n>>m;
	long long maxx=0,mid,cnt1=0,sum=0;
	for(long long i=1;i<=n;i++){
		cin>>a[i];
		maxx=max(maxx,a[i]);
		sum=sum+a[i];
	}
	long long L=maxx,R=sum;
	while(L<R){//二分答案查找
		mid=(L+R)>>1;
		if(check(mid)){//check函数
			R=mid;
		}
		else{
			L=mid+1;
		}
	
	}
	cout<<R;
		return 0;
}
三.【赛后总结】

今天的比赛成绩比上次进步了110分,我对这个成绩还是很满意的。(毕竟有人比我低)

我应该多多学习k4的知识,填补漏洞,保存代码时应该小心认真,仔细检查。争取下次模拟赛能够再有更大的进步!(@~@)---

最后给大家强调一下比赛保存过程:

1:编辑代码前应该先建好4个文件夹(别忘命名);

2:那四行代码不要写错,里面的题目名称也要及时写。

3:测试没有问题后记得取消四行代码的注释。

4;保存代码时记得彻底关闭C++(一定要!!!不然会考成原来的代码)

重要的四行代码:

#include<iostream>
using namespace std;
int main(){
freopen("题目名称(英文).in","r",stdin);
freopen("题目名称(英文).out","w",stdout);
代码部分
fclose(stdin);
fclose(stdout);
return 0;
     }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值