JAVA期末实验:CSP 201809-4 原题

因为防止作业重复,以及我抄我自己的情况出现,所以这里暂时只提供思路,不附代码。

卖菜(100分)

思路

这题没啥难的,注意两端计算方式是 ( a 1 + a 2 ) / 2 (a_1+a_2)/2 (a1+a2)/2 ( a n + a n − 1 ) / 2 (a_n+a_{n-1})/2 (an+an1)/2,而其他部分计算方式位 ( a i − 1 + a i + a i + 1 ) / 3 (a_{i-1}+a_i+a_{i+1})/3 (ai1+ai+ai+1)/3

买菜(100分)

思路

不能想当然地将两人时间段一对一地比较,要考虑极端情况。假如一个人的某个时段的结束时间比另一个人的结束时间要短,那么说明这个人的下一个时段也可能存在与另一个人同一段时间的交叠部分,因此继续将这个人的下一个时间段与另一个人的同一段时间相比,如此重复,直到其中一人的时间段都比较完了。时间复杂度最好情况O(n),最坏情况O(n^2)。

元素选择器(100分)

思路

对于单个的标签或者id查询是很容易实现的,难点在于如何处理后代选择器。这里有两个思路,

第一种思路构造树形结构,如图所示,这样很容易就能查到与当前点相关的子孙,按照深度遍历次序搜索后代即可;
树形结构

我采用的是第二种思路贪心策略,首构造一个文档每行内容的一个数据结构,要包含三个属性(级别、标签和id),根据题目提示的贪心策略,对于当前行,其后级别不大于他的都是他的子孙。按照这个思路我设置了一个答案ans数组和缓冲buf数组,遍历每一级查询,buf中存的是当前级别上一级查询的结果,逐个取出buf中的行号,从这个行号可是遍历查询他的子孙是否有当前要查询的东西。

注意查询和文档的标签要全部转换为小写(大写),此外,利用这种贪心的策略(树形结构思路也一样)会出现查询 div p 时会将 div div p 认为是两个 div p,这样就会出现重复,要注意去重

再卖菜(80分)

思路

用 a 表示第一天的价格,b 表示第二天的价格。

暴力方法:遍历所有商铺 a 的可能价格,进行验证,必定会TLE。

该题看似状态众多,但是除了缩小边界外,还可以根据数学关系以及已知的数来缩小状态数,这样就可以用dfs进行搜素了

我们首先分析题目,加上整除的计算方式,可以得到两端的关系式

2 ∗ b 1 < = a 1 + a 2 < = 2 ∗ b 1 + 1 2*b_1<=a_1+a_2<=2*b_1+1 2b1<=a1+a2<=2b1+1

2 ∗ b n < = a n − 1 + a n < = 2 ∗ b n + 1 2*b_n<=a_{n-1}+a_n<=2*b_n+1 2bn<=an1+an<=2bn+1

其他部分的关系式为

3 ∗ b i < = a i − 1 + a i + a i + 1 < = 3 ∗ b i + 2 3*b_i<=a_{i-1}+a_i+a_{i+1}<=3*b_i+2 3bi<=ai1+ai+ai+1<=3bi+2

对于两端关系式(以起始端为例),假如我们已经知道了 a 1 a_1 a1的值,那么 a 2 a_2 a2的值就会被限制在有限的两种可能中,即 2 ∗ b 1 − a 1 2*b_1-a_1 2b1a1 2 ∗ b 1 + 1 − a 1 2*b_1+1-a_1 2b1+1a1

同样地,对于其他部分关系式,如果我们已经知道了 a i − 1 a_{i-1} ai1 a i a_i ai的值,那么 a i + 1 a_{i+1} ai+1的值就会被限制在有限的三种可能中,即 3 ∗ b i − a i − 1 − a i 3*b_i-a_{i-1}-a_i 3biai1ai 3 ∗ b i + 1 − a i − 1 − a i 3*b_i+1-a_{i-1}-a_i 3bi+1ai1ai 3 ∗ b i + 2 − a i − 1 − a i 3*b_i+2-a_{i-1}-a_i 3bi+2ai1ai

这样,我们可以遍历 a 1 a_1 a1的所有可能,然后来搜索后续可能状态,这样可以保证之后每个点的状态都不会超过三种,只需要搜索到倒数第二个点即可得到 a 的序列,然后用末尾端的关系式进行验证

这样的dfs搜索策略可以拿到80分,当 n 很大时,搜索状态依然很多,还是会超时。

PS:这里有一个优化策略,即剪枝。我们已经知道,后一个值是有前两个值确定,那么当遍历到i点时,且访问了某种 a i − 1 a_{i-1} ai1 a i a_i ai的值的组合,那么不管其他值怎么变化,再次在i点时,这种组合必然也不可能成功,所以没必要对这种状态搜索下去。

使用这种剪枝策略实现的C++代码,能达到100分,但是,不知道为什么,Java剪枝后的时间效率反而不如不剪枝的,我猜测可能是因为使用了较大的vis数组,使得Java的gc机制耗时更多了。

线性递推式(20分)

思路

乍一看 l 可以很大,以为是数组内存不够的问题,再一看样例,好家伙还要考虑乘法溢出的问题,感觉巨难,没啥思路,只能暴力20分,这个代码不怕抄,可以附代码。

代码(20分)

import java.util.*;
public class q5 {
	private static Scanner sc;
	public static void main(String[] args) {
		sc=new Scanner(System.in);
		int m=sc.nextInt(),l=sc.nextInt(),r=sc.nextInt();
		sc.nextLine();
		long[] a=new long[r+1];
		long[] k=new long[100010];
		for(int i=1;i<=m;i++) {
			k[i]=sc.nextLong();;
		}
		a[0]=1;
		for(int i=1;i<=r;i++) {
			int min=(i<m ? i : m);
			for(int j=1;j<=min;j++) {
				a[i]=(a[i]+k[j]*a[i-j]%998244353)%998244353;
			}
		}
		for(int i=l;i<=r;i++) {
			System.out.println(a[i]);
		}
	}
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒商

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值