CSP-J模拟赛补题1

日期:2024年10月1日

学号:S14738

一、我的总分:
T1【交替出场(alter)】:20分

T2【翻翻转转(filp)】:0分

T3【方格取数(square)】:0分

T4【圆圆中的方方(round)】:10分

二、比赛概况:
T1【交替出场(alter)】: 

        看完题倒是有点思路,但是觉得不太可行,毕竟n≤1000的时候三层循环不太现实(算下来最多得有10的9次方了吧),又想了想也没有别的思路了,就先打上代码了,后来也没有什么思路,就没有再改,最后也是成功拿到了20%数据的分数。

T2【翻翻转转(filp)】:

        第一遍看完题觉得挺难的,后来在做的时候发现确实如此,就打的表(也没什么思路),在打了足足512个0和1以后(也就是第9个数),我觉得能得一点分,结果呢……嗯,0分。

T3【方格取数(square)】:

        也是很难的一道题,然后直接跳过了,最后再看就没时间写代码了(还是没什么思路),匆匆忙忙cout了样例的答案,也没对。

T4【圆圆中的方方(round)】:

        初一学生读完题表示比你还懵,学都没学过怎么算圆与矩形的重叠部分的面积,一看样例发现有一个可以骗分的地方,就cout了,但是只cout不给分啊啊!幸好后来又把分给我算上了。

三、比赛分析:
T1【交替出场(alter)】:

1、题目大意

        给定一个字符串,仅包含字符 0 或 1,求字符串中的 01 交替子串个数。

        01 交替串的定义是,前一位必须不同于后一位的字符串。

        特殊的,任意的长度为 1 的字符串也被定义为 01 交替串。

2、考试思路

        就是循环:

                01 交替串长度为 i

                01 交替串从第 j 项开始

                往后 i 位(判断能否形成01 交替串)

        事实证明思路不对

3、讲解后思路

       求从第 i 位开始的字符串个数,如果和上一位相等了就continue

4、AC代码

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int cnt;
string s;
int main(){
//	freopen("alter.in","r",stdin);
//	freopen("alter.out","w",stdout);
	cin >> s; 
	int len = (int)s.size();
	for(int i = 0;i < len;i++){
		//任意的长度为 1 的字符串也被定义为 01 交替串,cnt要加上长度为 1 字符串数量 
		cnt++;
		for(int j = i+1;j < len;j++){
			//01 交替串的定义是,前一位必须不同于后一位的字符串,所以 s[j] 不能等于 s[j-1]
			if(s[j] != s[j-1]){
				cnt++;
			}else{
				break;
			}
		}
	}
	cout << cnt;
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

T2【翻翻转转(filp)】:

1、题目大意

        gza 有一系列的字符串,第 ii 个名为 s_is​i​​。

        s_0 = 1

        s_1 = 10

        s_2 = 1001

        s_3 = 10010110

        ⋯⋯

        s_​i​​ 是s​_i−1​​ 逐位取反后拼接在 s_​i−1​​ 后的串。

        你需要求s_​114514​​ 的第 x 个字符是什么。

        多测。

2、考试思路

        没有思路,就想着打表呗,最后也没得分

3、讲解后思路

        类似二分查找思路,在左边不改,在右边按位取反,直到找到答案

4、AC代码

#include<iostream>
#include<cstdio>
using namespace std;
int t,x;
void fun(int l,int r,bool p){
	//l==r 说明找到了答案,直接输出 
	if(l == r){
		cout << (p == true ? 1 : 0) << endl;
		return;
	}
	int mid = (l+r)/2;
	//二分算法 
	if(x<= mid){
		fun(l,mid,p);
	}else{
		//!p是因为右半边要按位取反 
		fun(mid+1,r,!p);
	}
}
int main(){
//	freopen("filp.in","r",stdin);
//	freopen("filp.out","w",stdout);
	cin >> t;
	while(t--){
		cin >> x;
		//1 << 30表示将数字1的二进制形式左移30位,转换为十进制后等于2^30 
		fun(1,1 << 30,1);
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

T3【方格取数(square)】:

1、题目大意

        想必大家都做过方格取数吧。

        现在,你需要做一个特殊的方格取数。

        每个格子都有一个数字,走过便能收集,也必须收集。

        你从 (1,1)(1,1) 出发,目标是 (n,m)(n,m),只能向右或者向下走,但是你不能一次性往一个方向走大于等于 kk 步。

        求收集到的数字的和的最大值。

        如果无解,输出“No Answer!

2、考试思路

        感觉dfs可以,但是有了步数限制就是不知道怎么实现

3、讲解后思路

        要用到四层循环和四维数组,确实是dfs的思路(移动->判断出界->判断状态->赋值)

4、AC代码

#include<bits/stdc++.h>
using namespace std;
long long f[210][210][210][2],a[210][210];
int n,m,k;
int dx[2] = {0,1};
int dy[2] = {1,0};
int main(){
//	freopen("square.in","r",stdin);
//	freopen("square.out","w",stdout);
	cin >> n >> m >> k;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= m;j++){
			cin >> a[i][j];
		}
	}
	memset(f,-0x3f,sizeof f);
	f[1][1][0][0] = f[1][1][0][1] = a[1][1];
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= m;j++){
			for(int l = 0;l < k;l++){
				for(int d = 0;d <= 1;d++){
					//没有对应状态 
					if(f[i][j][l][d] < -4e9){
						continue;
					}
					for(int dd = 0;dd <= 1;dd++){
						//移动 
						int x = i+dx[dd];
						int y = j+dy[dd];
						//判断出界 
						if(x>n || y>m){
							continue;
						}
						//这一次移动的位置与上一次是否相同并对相应状态赋值 
						if(d!=dd){
							f[x][y][1][dd] = max(f[x][y][1][dd],f[i][j][l][d]+a[x][y]);
						}else{
							f[x][y][l+1][dd] = max(f[x][y][l+1][dd],f[i][j][l][dd]+a[x][y]);
						}
					}
				}
			}
		}
	}
	long long maxx = -4e9;
	for(int l = 0;l < k;l++){
		for(int d = 0;d <= 1;d++){
			maxx = max(maxx,f[n][m][l][d]);
		}
	}
	if(maxx == -4e9){
		cout << "No Answer!";
	}else{
		cout << maxx;
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

T4【圆圆中的方方(round)】:

1、题目大意

        你有一个四个边界点为 (0,0),(n,0),(0,m),(n,m) 的矩形。

        有一点 A(a,b) 保证 A 在矩形内部或边界上,求以 A 为圆心,半径为 r 的圆与矩形的重叠部分的面积。

2、考试思路

        我真没学过,不会,单纯就骗个10分

3、讲解后思路

         要用到三角函数(如图),代码很麻烦,分很多种情况,要一个一个判断

4、AC代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double eps = 1e-8;
double S(double x,double y,double r){
	if(x<eps || y<eps){
		return 0;
	}
	//判断 x > r 且 y > r ,取圆面积的四分之一 
	if(x > r && y > r){
		return (M_PI*r*r)/4;
	}
	//其他情况将圆与矩形的重叠部分的面积分成三角形和扇形分别计算 
	if(x > r){
		double x_ = sqrt(r*r-y*y);
		double ang = atan(y / x_);
		return ang/2*r*r+y*x_/2;
	}else if(y > r){
		double y_ = sqrt(r*r-x*x);
		double ang = atan(x / y_);
		return ang/2*r*r+x*y_/2;
	}
	double x_ = sqrt(r*r-y*y);
	if(x_ > x){
		return x*y;
	}
	double ang1 = atan(x_/y);
	double y_ = sqrt(r*r-x*x);
	double ang2 = atan(y_/x);
	double ang = M_PI/2-ang1-ang2;
	return (ang/2*r*r)+x*y_/+y*x_/2;
}
int main(){
//	freopen("round.in","r",stdin);
//	freopen("round.out","w",stdout);
	double n,m,a,b,r;
	cin >> n >> m >> a >> b >> r;
	//圆的上下左右四部分面积和 
	double ans = S(n-a,m-b,r)+S(a,m-b,r)+S(a,b,r)+S(n-a,b,r);
	printf("%.10lf\n",ans);
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}

四、反思&总结:

        能写代码写代码,尽量不要去骗分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值