CSP - S 2024 模拟赛5补题报告

C S P   −   S    2024   模拟赛 5   补题报告 2024 年 8 月 2 日 − 2023 年 8 月 2 日 b y    邓时飏 CSP \ - \ S \ \ 2024 \ \ 模拟赛5 \ \ 补题报告 \\ 2024年8月2日 - 2023年8月2日 \\ by \ \ \ 邓时飏 CSP  S  2024  模拟赛5  补题报告202482202382by   邓时飏

一、做题情况

  • 第一题比赛 0 0 0 / 100 100 100 ,赛后通过

  • 第二题比赛 0 0 0 / 100 100 100 ,赛后通过

  • 第三题比赛 0 0 0 / 100 100 100 ,赛后通过

  • 第四题比赛 0 0 0 / 100 100 100 ,赛后通过

  • 比赛得分 0 0 0 / 400 400 400 ,赛后补题 400 400 400 / 400 400 400

二、题解报告

T1:

题面:

在这里插入图片描述

在这里插入图片描述

做法:

过预处理来构建 nxt 和 las 数组,然后利用这两个数组在常数时间内回答每个查询。预处理部分的时间复杂度是 O(n),每个查询的处理时间是 O(1),因此总的时间复杂度是 O(n + q),

附:AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5000010;
int a[N], nxt[N], las[N];
int n, q;
inline int read() {
    int x = 0; 
    bool flag = 0; 
    char ch = getchar();
    while (!isdigit(ch)) flag = (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return flag ? -x : x;
}
signed main() {
    freopen("hot.in", "r", stdin);
    freopen("hot.out", "w", stdout);
    cin >> n >> q;
    for (int i = 1; i <= n; ++i) a[i] = read();
    for (int i = 1; i <= n; ++i) {
        if (a[i] >= a[i - 1]) nxt[i] = max(nxt[i], nxt[i - 1] + 1);
        else nxt[i] = 1;
    }
    for (int i = n; i >= 1; --i) {
        if (a[i] >= a[i + 1]) las[i] = max(las[i], las[i + 1] + 1);
        else las[i] = 1;
    }
    int l, r;
    for (int i = 1; i <= q; ++i) {
        l = read(), r = read();
        if (nxt[r] + las[l] >= r - l + 1) cout << 'Y' << endl;
        else cout << 'N' << endl;
    }
    return 0;
}

T2:

题面:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

做法:

从右向左遍历细胞数组,通过不断地将每个细胞分割成较小的部分,并确保每次分割后的最大部分大小不超过当前的最小值。这样可以确保通过最少的劈砍次数使整个数组成为非递减序列。

附:AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int a[N];
long long ans;
int c;
int main() {
    freopen("divide.in", "r", stdin);
    freopen("divide.out", "w", stdout);
    scanf("%d", &n);
    for (register int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    int mm = a[n];
    for (register int i = n - 1; i > 0; --i) {
        int pnum = ceil(a[i] * 1.0 / mm);
        ans += pnum - 1;
        mm = a[i] / pnum;
    }
    printf("%lld", ans);
    return 0;
}

T3:

题面:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

做法:

通过动态规划的方法分别从横向和纵向两个方向计算矩阵中可能的最大路径和,然后将这两个结果相加,得到最终的最大价值和。这样的设计能够有效地处理路径和的问题,同时保证计算的效率。

附:AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e3;
int n, m,a[N+5][N+5],dp[N+5],ans;
int main() {
    freopen("tunnel.in","r",stdin);
    freopen("tunnel.out","w",stdout);
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    cin >> n >> m;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++) cin >> a[i][j];
    }
    for(int i=1; i<=n; i++) {
        for(int j=2; j<=m; j++) dp[j] = max(dp[j-2] + max(0, a[i][j-1] + a[i][j]), dp[j-1]);
        ans += dp[m];
    }
    dp[1] = 0;
    for(int i=1; i<=m; i++) {
        for(int j=2; j<=n; j++) dp[j] = max(dp[j-2] + max(0, a[j-1][i] + a[j][i]), dp[j-1]);
        ans += dp[n];
    }
    cout << ans << "\n";
    return 0;
}

T4:

题面:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

做法:

在一个长度为 n 的数组 a 中,找出某种最大值(可能是最长的递增子序列或最大权值和,具体取决于题意)。代码使用了线段树来加速区间查询和更新操作。

附:AC代码
#include<bits/stdc++.h>
using namespace std;
const int Max_N=2e5;
int n,cnt,a[Max_N+5],pos[Max_N+5],nxt[Max_N+5],R[Max_N+5],rp[Max_N+5];
struct Tree{ int l,r,Mn; } A[Max_N*4+5];
vector<int> p[Max_N+5];
void Build(int x,int l,int r){
	A[x].l=l; A[x].r=r; A[x].Mn=n+1;
	if(l==r) return ;
	Build(x<<1,l,(l+r)>>1);
	Build((x<<1)|1,((l+r)>>1)+1,r);
}
int Ask(int x,int k){
	if(k<=A[x].l&&k<=A[x].Mn) return A[x].r;
	if(A[x].l==A[x].r) return 0;
	if(k<=A[x<<1].r){
		int t=Ask(x<<1,k);
		if(t==A[x<<1].r){
			int w=Ask((x<<1)|1,k);
			if(w) return w;
			else return t;
		} else return t;
	}
	return Ask((x<<1)|1,k);
}
void Add(int x,int p,int w){
	if(A[x].l==A[x].r){
		A[x].Mn=w;
		return;
	}
	if(p<=A[x<<1].r) Add(x<<1,p,w);
	else Add((x<<1)|1,p,w);
	A[x].Mn=min(A[x<<1].Mn,A[(x<<1)|1].Mn); 
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),p[a[i]].push_back(i),rp[i]=p[a[i]].size();
	for(int i=n;i>=1;i--) pos[i]=n+1;
	for(int i=n;i>=1;i--){
		nxt[i]=pos[a[i]];
		pos[a[i]]=i;
	}
	Build(1,1,n);
	long long ans=n;
	for(int i=n;i>=1;i--){
		if(nxt[i]==n+1||i+1>nxt[i]-1||R[i+1]<nxt[i]-1||a[i+1]!=a[nxt[i]-1]) R[i]=i;
		else {
			int rans=R[nxt[i]];
			rans=min(rans,Ask(1,nxt[i]));
			if(rans==0) R[i]=nxt[i],++ans;
			else {
				int x=upper_bound(p[a[i]].begin(),p[a[i]].end(),rans)-p[a[i]].begin();
				R[i]=p[a[i]][x-1]; ans+=x-rp[i];
			}
		}
		if(nxt[i]<=n) Add(1,nxt[i],i);
	}
	printf("%lld\n",ans);
	return 0;
} 

四、赛后总结

提升实力,控制时间。

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值