CSP-J第一场模拟赛补题报告2024.10.1

一、题目报告

比赛中第一题10分,第二题60分,第三题50分(1组数据),第四题10分;比赛后AK。

二、赛中概况

前一个小时觉得第一题要算法,先打的第二题,打了一个小时没想到正解思路,就打了暴力开下一题。第一题20分钟写完(最后爆10了),第三题一眼dp不会写(烦)写了dfs,第四题直接不会,输入样例骗了10分。(一道题的正解都没想出来的考生是屑)

三、解题报告

T1.交替出场(alter)

题目情况

比赛时10pts。

题目大意

给定一个01字符串,求其中01子串个数

题目解析

直接枚举每个子串会超时,所以我们枚举左端点和右端点,并且枚举右端点时,只要发现不匹配就直接break,节省复杂度

正解代码
#include<bits/stdc++.h>
using namespace std;
string s;
int main(){
	cin>>s;
	s=' '+s;
	int ans=0,len=s.size();
	for(int i=1;i<len;i++){
		ans++;
		for(int j=1+i;j<=len;j++){
		    if(s[j]+s[j-1]=='0'+'1'){ans++;}
		    else break;
		}
	}
	cout<<ans;
    return 0;
}


T2.翻翻转转(filp)

题目情况

比赛时60pts。

题目大意

字符串s_{i}s_{i-1}逐位取反后拼接在s_{i-1}后的串。你需要求s_{114514}(?的第$x$个字符是什么。

题目解析

x<=1e9,这样的数据范围只能用O(log_{n}),用logn复杂度的算法中可以推出二分。

正解代码

#include<bits/stdc++.h>
using namespace std;
int x;
void fun(int l,int r,int p){
    if(l==x&&r==x){
        cout<<(1==p)<<endl;return;
    }
    int mid=(l+r)/2;if(x<=mid)fun(l,mid,p);
    else fun(mid+1,r,-p);
}
int main(){
	int t;
	cin>>t;
	while(t--){
	    cin>>x;
	    fun(1,1<<30,1);
	}
    return 0;
}

T3.方格取数(square)

题目情况

比赛时50pts。

题目大意

NOIP方格取数,但有步数限制

题目解析

本题需要用dp进行完成,重点是推导状态转移方程。

正解代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 210;
ll dx[2] = {1, 0}, dy[2] = {0, 1};
ll n, m, k, a[N][N], dp[N][N][N][2], ans = -1e18;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> k;
	for (ll i = 1; i <= n; i++)
		for (ll j = 1; j <= m; j++)
			cin >> a[i][j];
	memset(dp, -0x3f, sizeof(dp));
	dp[1][1][0][0] = dp[1][1][0][1] = a[1][1];
	for (ll x = 1; x <= n; x++)
		for (ll y = 1; y <= m; y++)
			for (ll l = 0; l < k; l++)
				for (ll d = 0; d <= 1; d++) {
					if (dp[x][y][l][d] < -1e18)continue;
					for (ll nd = 0; nd <= 1; nd++) {
						ll nx = x + dx[nd], ny = y + dy[nd];
						if (nx < 1 || nx > n || ny < 1 || ny > m)continue;
						if (d != nd)
							dp[nx][ny][1][nd] = max(dp[nx][ny][1][nd], dp[x][y]
							                        [l][d] + a[nx][ny]);
						else if (l < k - 1)
							dp[nx][ny][l + 1][nd] =max(dp[nx][ny][l + 1][nd], dp[x][y][l][d] +
							                           a[nx][ny]);
					}
				}
	for (ll l = 0; l < k; l++)
		for (ll d = 0; d <= 1; d++)
			ans = max(ans, dp[n][m][l][d]);
	if (ans == -1e18)
		cout << "No Answer!";
	else
		cout << ans;
	return 0;
}

T4.圆圆中的方方(round)

题目情况

比赛时10pts。

题目大意

给你矩形的四顶点和一个⚪的圆心和半径,求正方形与⚪重合的面积

题目解析

数学题

在sub2中,r \leqslant \sqrt{n^{2}+m^{2}},根据勾股定理可以看出r>m,r>n,则圆完全覆盖矩形,答案为n*m

在sub3中,r \leq min(a,b,n-a,m-b),则矩形完全覆盖圆,答案为\pi r^{2}

正解代码

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1), eps = 1e-6;
double n, m, x, y, r;
double calc(double n, double m, double r) {
	if (n > m)
		swap(n, m);
	if (n < eps || m < eps)
		return 0;
	if (r <= n)
		return 0.25 * pi * r * r;
	else if (r <= m) {
		double tt = sqrt(r * r - n * n);
		double res = n * tt / 2.0;
		double ang = pi / 2 - acos(n / r);
		res += ang / 2 * r * r;
		return res;
	} else if (r <= sqrt(n * n + m * m)) {
		double t1 = sqrt(r * r - n * n), t2 = sqrt(r * r - m * m);
		double res = n * t1 / 2.0 + m * t2 / 2.0;
		double ang = pi / 2 - acos(n / r) - acos(m / r);
		res += ang / 2 * r * r;
		return res;
	} else
		return n * m;
}
int main() {
	cin >> n >> m >> x >> y >> r;
	cout << fixed << setprecision(10)
	     << calc(x, y, r) + calc(x, m - y, r) + calc(n - x, y, r) +
	     calc(n - x, m - y, r)
	     << endl;
	return 0;
}

四、总结

本场考试中,我的思路没有跟上,错过了一些掌握的算法,复杂度没有计算好,导致第一题失误,仍需努力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值