CSP-J复赛模拟赛5 王晨旭补题 2026.10.5

一,前言

今天大概是5场模拟赛打的最好的一把了,除了刚开始30分钟的时候睡得有点懵之外,剩下的时间状态都不错诶,也算是对5天的集训进行了一个良好的收尾,虽然打的还不错,但是也有细节和可惜的地方值得后续的注意,让我们来看一看这套题目

补完题四后:气死我了啊啊啊啊啊啊啊啊啊啊稳上300班级Rank1啊啊啊啊气死我了这个细节把控

二,成绩

1,稳住读数【100/100】炮灰你好

2,漏掉的指令【85/100】没有了过往的记忆,那我又算是什么

3,应急通行【25/100】你这家伙老老实实去第四题或者提高组去啊!!!

4,分批烘干【25/100】假如我再给你一些时间,亲爱的,你还会给我一个机会吗(我恨你)

总分:【235/400】今日班级rank 4(开心诶) 注意T4最高分【25/100】

这套题呢与前年没有任何相同的题目,这样也好,没有任何水分在了,题目依旧官方认证的难哦

(还我树组!!!!!让我再做一次吧(哭))

补完题四后:嗯我可以说我原本应该325分的吗

补充

1,题一还是不说了,但是这回还是小创我一下打了40分钟才过,只能说进入状态是很重要的,关于语法题的思路还是建议写写注释,这会也有一定的审题错误,一定审好再做!!!

2,本次官方认证难度 3>2>4>1

三,题四

在补题之前,我对我的25分沾沾自喜,认为走运了打了班里第一,但是补完之后,我直接将它的顺序放到了第一个(我的专属)

好好好,你终于来了,这是我第一个AC的第四题,这是我第一个用20分钟做完的第四题

显然这个题是不好做的,班级最高分25啊,但是,它撞上了巅峰状态的我

那我直接神挡杀神佛挡杀佛,直接写了一篇换3个字符就AC的代码

没!开!long!long!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊我分没了

每年都有,我原本以为今年已经逃过去了啊啊啊啊啊啊然而没有

我相信我是整个班对待补题报告最认真的,也确实管用,除了long long之外我的代码完全正确,这基本归功于我对每套模拟赛第3,4题的补题报告,重点在26年第一次模拟补题的第4题

本题基本与之类似吧,甚至我觉得更简单,状态全部写对了,简单看一下这个题直接过吧

实验室有 n 份样品,按编号 1∼n 排列。样品 i 的最低烘干强度为 a​i​​,完成处理后可以获得 vi​​ 点研究价值。

实验员可以选择部分样品,分成若干批处理,规则如下:

每批必须是原序列中的一个非空连续区间 l,r,这一批包括编号从 l 到 r 的全部样品。

不同批次不能重叠,每份样品最多处理一次;两个批次可以紧挨着,例如 1,2 和 3,3 可以分别处理。

可以跳过样品,但跳过后,原本不相邻的样品不能直接拼成一个批次。例如跳过第 2 份后,第 1、3 份仍不能单独组成一批。

处理一批 l,r 时,机器采用该批样品中最大的烘干强度。设每次启动的固定能耗为 C,则这一批消耗的能量为C+(r−l+1)×max l≤i≤r ai

获得的研究价值为∑i=l到r vi

实验室的总能量预算为 B,要求所有批次消耗的能量之和不超过 B。

请你求出最多能够获得多少总研究价值。允许一份样品都不处理,此时总能耗和总价值均为 0。

思路如下,非常简单:

题意:可以把连续若干物品打包为一组。

一组的代价 = C + 组内物品数量 × 组内a的最大值;一组价值 = 组内所有v相加。

DP状态定义:dpij = 处理前i件物品,花费代价j,能获得的最大价值。

转移两种选择:

  1. 不把i放进新组:继承dpi-1j

  2. 枚举左端点k,将k~i打包成单独一组: 维护区间k,i的a最大值,计算本组代价sumc、价值sumv。 若预算足够,则从dpk-1j-sumc转移,更新dpij。

AC代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
long long dp[405][2005];
int main(){
	//freopen("dry.in","r",stdin);
	//freopen("dry.out","w",stdout);
	int n,B,C,v[405],a[405];
	cin>>n>>B>>C;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>v[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=B;j>=0;j--){
			dp[i][j]=max(dp[i][j],dp[i-1][j]);//完全不选
			//往前找进行组合
			long long sumc,sumv=0;
			int maxx=a[i]; 
			for(int k=i;k>=1;k--){//只选一个作为一批次也要算k=i 
				maxx=max(maxx,a[k]);
				sumc=C+1ll*(i-k+1)*maxx;
				sumv+=v[k];
				if(j<sumc)	break;
				dp[i][j]=max(dp[i][j],dp[k-1][j-sumc]+sumv);
			} 
		}
	}
	cout<<dp[n][B];
}

写这个的主要目的还是警醒自己必须开long long(其实我写的时间复杂度什么的都符合条件,一直没想到能A,long long根本就没想到这回事)

四,题二

好了真正第四题来袭

p1:过往题二的记忆失效之后才想起来我24年被第二题被创的有多惨啊,不可小觑

p2:这边可以考虑删掉思维题吗,第二题就老老实实的给我出大模拟啊喂

p3:呜呜呜呜我的分啊啊啊,细节把握和反例举证真的太难了啊啊啊啊

p3:注:思路和算法完全正确,改掉一处细节4个字符直接AC

心理状态结束(今年心态好好啊,这个题可是做了2个小时呢,越做越爽,越做越有感觉,越做不出来越想做,相比24年的又哭又闹,现在才是正确状态)

我们来一起看一下这道思维好题(数学题)结尾再说说细节的把控,先看题面

一个循环计数器初始显示 0。计数器的显示值始终是 0 到 m−1 中的整数。

原计划依次执行 n 条指令,每条指令是以下两种之一:

+ a:将当前显示值加上 a,然后对 m 取模。

* a:将当前显示值乘以 a,然后对 m 取模。

执行结束后,工作人员怀疑发生过漏执行故障,希望按照以下情况核对记录:恰好有一条指令没有执行,其他指令仍然按照原来的顺序正确执行。

现在给出原计划的全部指令,以及执行结束后记录的数 r。请你计算,有多少个遗漏位置能够在上述情况下得到 r。不保证工作人员的推测一定成立。

位置不同就视为不同的可能,即使两个位置上的指令内容相同。执行一条指令后数值可能保持不变,这样的指令也可能是遗漏指令。允许乘以 0,且 m 不一定是质数。

如果没有任何一个遗漏位置能够得到结果 rr,输出 0。如果 n=1,遗漏唯一的指令后不再执行任何指令,计数器保持初始显示 0。

先简单说说官方思路(我的思路虽与其不同,但也是正解),对于思维题,自己的做法才是重中之重

仿射变换法!(呦呦呦又装上了):这次不一样,不是直接复制粘贴,我用自己的话把它说明白

我们设置一个转换器,不要管放进去它的东西是什么,也不用管输出的东西是什么,我们设计的转换器就是打包一段操作,不管把什么扔进去,都会对这个东西进行这个转换器打包的这段操作,然后给一个输出值

这个转换器我们把它命名为f(x),本题的操作只有+,*两种

所以我们的转换器大概长这样f(x)=Ax+B(mod m),加法乘法定义来说,初始A=1,B=0

若我们此时对一段操作求它对应转换器的AB(一次函数k,b)

  • 7 A=1,B=7

* 3 A=3,B=21

+4 A=3,B=25

那这一段操作的对应的转换器就是f(x)=Ax+B(mod m)=3x+25(mod m)

扔进一个x就会得到f(x)是3x+25,这个值等价于对x执行+7 *3 +4的操作

直接把这一段操作的信息直接转换成两个数

我们此时有一些前缀的操作和后缀的操作,对应设置结构体数组pre\[\],suf\[\]

我们对于前i项操作,按上述递推方式,得到转换器prei.A,prei.B,此时就有x=x*prei.A+prei.B,将x执行前i项操作后的值更新给x

我们对于i到n项(末i项)操作,继续递推(类似后缀和)得到转换器sufi.A,sufi.B,此时就有

x=x*sufi.A+sufi.B,将x值执行第i到第n项操作后的值更新给x

我们如果要扔掉第k个操作,就是把初值扔到prek-1中,这样获得了经过第1个操作到k-1个操作的值,再把这个新值扔到sufk+1中,对它执行第k+1次操作到n次操作,得到的值就是遗弃第k次操作的值,这是显而易见的

正片开始,考场思路来了

p1:我们去考虑每个运算对于最终答案的贡献,观察到有一个特殊样例全部都是加法运算,这种样例中,遗弃一个运算就是在最终结运算果里面减去这个加数("减去"伏笔),也给我们埋下了 "扣掉贡献" 的思路

p2:这种情况是朴素的,那加上乘法之后呢?我们希望将这些操作转化为这种(x+y+z+a+b+c...+w)朴素情况,所以我们将乘法转为加法考虑!

对于这样一个运算7*3,显然它等效于7+14

对于这样一个运算A*B,显然它等效于A+A*(B-1)

这个A不是代表一个数,而是在计算*B这个运算之前,前面所有运算后得到的值即执行这条乘法指令之前,计数器已经算出的值

A这个东西我们通过前缀打表来求解

所以*B这个运算就转化为了+A*(B-1)

这样我们把乘法转化为了形式上的加法,就是把 "多出来的增量" 变成加法

p3:这里我们得到原本的加法和乘法转为的加法,显然这两种加法并不与那种朴素情况中的加法相同,我们考虑乘法分配律,将其转化为真正意义上的"加法"

考虑这么一个式子

(7+4)\*3+5*2

+7这个运算的贡献怎么算?把式子用分配律拆开

7*3*2+4*3*2+5*2

+7变成了+7*3*2

+5变成了+5*2

没错,我们加法的转为朴素形式就是乘上后面所有乘法累乘起来的乘积,得到这样的一个真正的加法,可以利用p1的方法直接求解

那我们在上一步乘法转化为的形式加法,显然也要再转换成为真正的加法,乘上后面所有乘法累乘起来的乘积,再去使用p1的方法进行求解

我们前文所说的"真正的加法",就是每个值对于最终答案的贡献,我把这个求法叫做贡献法

AI润一下:把乘法等效改为虚拟加法,再利用分配律,预处理出每条指令后方所有乘法的乘积,算出单条加法指令对最终答案的总贡献。跳过该指令等价于从总结果减去这份贡献

注意模运算相关两个点:

1,模运算添加的位置是有影响的,显然不是所有运算的位置都能无脑套上取模,我被坑完自己调出来了

2,这边非常难调,虽然很难想,但是真的有样例是这样的,一个运算的贡献大于总结果,哇也是直接给我卡掉15分,%运算取模结果与被除数符号一致,但显然我们题目要的是非负数,所以回顾一下模运算减法(A-B)%m一定要这么写(A-B)%m+m%m

看完T4的大坑我觉得这15分也无所吊谓了

AC代码

cpp 复制代码
//乘法转化为加法:设该乘法前面所有数的运算结果为x(前缀打表求解) 
//运算该乘法*A后得到结果为x*A,该乘法可被转化为x+(A-1)*x 
//即将*A转化为+(A-1)*x,x的求解利用前缀打表 
//删除x即结果直接减去 
//删除加法带来的影响是容易计算的 
//其后面所有乘法的乘积(乘法分配律)乘以该加法即为该加法对答案的贡献 
#include<bits/stdc++.h>
const int N=2e5+5;
using namespace std;
char op[N];
int n,m,r;
long long a[N],sum[N],f[N];
int main(){
	freopen("omit.in","r",stdin);
	freopen("omit.out","w",stdout);
	scanf("%d%d%d",&n,&m,&r);
	for(int i=1;i<=n;i++){
		scanf("%s%lld",&op[i],&a[i]);
		if(op[i]=='+')	sum[i]=sum[i-1]+a[i];
		else if(op[i]=='*')	sum[i]=sum[i-1]*a[i];//嘻嘻
		sum[i]%=m;
	}
	f[n]=1;
	for(int i=n-1;i>=1;i--){
		f[i]=f[i+1];
		if(op[i+1]=='*')	f[i]*=a[i+1];
		f[i]%=m;	
	}
	int cnt=0;
	for(int i=1;i<=n;i++){
		long long final=sum[n];
		if(op[i]=='+')	final+=m-1ll*a[i]*f[i]%m;
		else if(op[i]=='*')	final+=m-1ll*sum[i-1]*(a[i]-1)*f[i]%m;
		final%=m;
		if(final==r)	cnt++;	
	}
	cout<<cnt;
} 

五,题三

这边赛上也是非常简单且诡异。毫无思路,想暴搜,又想到昨天说找短路不能用dfs,再看了眼数据,于是放弃,由于接触过提高组知识,莫名想到了单源最短路?迪杰斯特拉?!误闯天家。那只能宽搜了,其实这就是正解,但昨天被误导了说带权图不可以用bfs跑最短路,也倒是歪打正着去做了第4题然后。。。

回来看到有部分数据非常诡异的是一条链?(?强强?!)

直接跑了二分答案拿到25分(二分答案也是正解)

这个题的赛后更是诡异至极,老师没有讲正解思路(我不知道)

问豆包给出了与题解截然不同的解法,我对着写了半天题解好多好多字结果她自己没AC,而官方题解非常难想不好弄,说骗分思路也没啥必要了(55分是容易获得的)

豆包写的。。。应该是官方的70分思路,但是落下来就成了15分,这个题的正解是多源BFS和正反向搜索

给定有向图,n个站点,m条单向道路。每条道路有通行要求ai。 有起点S、终点T,应急模式最多连续走K条道路,基础能力P

移动规则: 整条路径分为三段(可以某段为空):

  1. 普通模式:只能走ai<P的道路;
  2. 应急模式:可走任意道路,连续最多 K 条边;
  3. 普通模式:只能走ai<P的道路。

求满足条件的最小P

嗯这是根据正解思路反推整理出的题面,实际做的时候还有从题面转成上述文字的需要(饿啊)

对于每个P(二分答案中的mid):

大致就是正向从起点跑一遍BFS,只走直接能到不开应急ai<P的路,路上的点就是第二段的开始点,反向从终点跑一遍BFS,只走直接能到不开应急的路,路上的点就是第二段的结束点

然后对正向BFS跑出的所有点跑BFS(起点有多个就是多源最短路),看看能不能有在距离小于K时遍历到标记好的结束点,若有则证明该P可行

那这个题就这样吧。。。悲催

六,总结

不要骄傲,还是要以稳定,专注,细心的状态来背赛,应赛,加油!注意细节,模运算负数,long long问题,时间把握,能骗则骗,我们赛场见!

七,祝福

这里也要祝福自己啦,祝前程似锦

相关推荐
罗湖老棍子2 小时前
C Looooops(信息学奥赛一本通- P1640)
算法·数论·同余·裴蜀定理·扩展欧几里得
飘尘5 小时前
从"算子"到"AI Infra":大模型背后看不见的那群人在忙什么
人工智能·算法·面试
夏幻灵5 小时前
每日一题:LeetCode 3:无重复字符的最长子串——滑动窗口思路详解
算法·leetcode·职场和发展
CarIise6 小时前
Java实训阶段查漏补缺复习笔记2
java·linux·算法
无忧.芙桃6 小时前
C++ 并查集详解:原理、实现与应用
c语言·c++·算法·leetcode
蛋蛋的就会顺顺的6 小时前
hot100——二叉树
java·数据结构·算法·leetcode·力扣
Code_Solitude7 小时前
c语言:二分法的完整补充
c语言·开发语言·算法
一切皆是因缘际会7 小时前
掌控信息论:同源星际通信基础理论
人工智能·算法·ai
动词ing9 小时前
【C语言题目练习】算法 整数反转
c语言·开发语言·算法