CSP-S2025模拟赛

CSP-S模拟赛5

A.十年之约

一道黄题。我们容易发现:
\(f(i) = k \Longleftrightarrow lcm(1, 2, 3, \cdots, k - 1) \mid i, lcm(1, 2, 3, \cdots, k) \nmid i。\)
发现n数据范围过大,可以考虑枚举答案。看到上面的式子,可以容易地预处理出来前缀lcm:\(a_k\)。然后每次给答案加上$\left \lfloor \dfrac{n}{a_k} \right \rfloor - \left \lfloor \dfrac{n}{a_{k + 1}} \right \rfloor $直到这个式子答案为0。

启示:考虑对题目条件进行翻译,发现了lcm的等价式子就容易了。

B.可爱三小只

并不难,但是场上没有想出来。容易知道,选择行和列的顺序对结果没有任何影响。所以可以考虑行和列分别贪心,记录答案,最后枚举行和列分别使用的次数,合并答案。
具体地,就是使用一个优先队列,一直取出堆顶,修改后放回去,把值记下来,最后两种合并时减掉\(i \times (K-i) \times p\)即可。

启示:一个经典的套路:枚举加贪心,两周前模拟赛的C也是这个大方向。并且不要预设题目难度,这个题只是绿。

C.蛋糕塌了

首先需要发现很重要的东西:排序不影响答案。
所以给原数组排好序,考虑两个下标\(i\)\(j\),可以得到这一段对期望的贡献是\(\dfrac{a_i a_j}{2^{j - i + 1}}\),就是中间不能放任何其他数。

对于单点修改,我们需要用数据结构维护。然后设对于一段区间\([l,r]\),取它的中点\(mid\)进行合并:
\(\Large \sum_{i=l}^{mid} \sum_{j=mid+1}^{r} \dfrac{a_i a_j}{2^{j - i + 1}} = \dfrac{a_i}{2^{mid - i + 1}} \times \dfrac{a_j}{2^{j - mid}}\)
所以我们需要维护每一段的答案\(F\),每个点到l的前缀和\(G\),到r的后缀和\(H\),一段之间的当前元素个数\(siz\)(因为是先离散化,树上会有一些给修改预留的空位,或者其中元素已经被删除的空位,所以要维护siz)。
然后合并信息的式子应当是简单的,我认为最难的部分还是离散化。
因为相同元素间也有贡献,所以需要把这些元素离散化到不同的位置。注意离散化之后的元素值应当是线段树里面的下标。代码放一下比较重要的cal函数。

点击查看代码
void cal()
{
	Tr.build(1, 1, n + q);//这是权值线段树,所以有n+q种离散化之后的权值作为下标 
	for(int i = 1; i <= n; i++)
		Tr.modify(1, aa[i], a[i], 1);
	cout << Tr.tr[1].F << "\n";
	for(int i = 1; i <= q; i++)	
	{
		Tr.modify(1, aa[p[i].first], 47, 0);
		aa[p[i].first] = vv[i];
		Tr.modify(1, vv[i], p[i].second, 1);
		cout << Tr.tr[1].F << "\n";
	}
}

signed main()
{
//	freopen("cake.in", "r", stdin);
	
	cin >> n;
	for(int i = 1; i <= n; i++)cin >> a[i], b[i] = a[i];
	cin >> q;
	for(int i = 1; i <= q; i++)cin >> p[i].first >> p[i].second, b[i + n] = p[i].second;
	sort(b + 1, b + n + q + 1);
	for(int i = 1; i <= n; i++)
		cnt[a[i]]++, aa[i] = lower_bound(b + 1, b + n + q + 1, a[i]) - b + cnt[a[i]] - 1;
	for(int i = 1; i <= q; i++)
		cnt[p[i].second]++, vv[i] = lower_bound(b + 1, b + n + q + 1, p[i].second) - b + cnt[p[i].second] - 1;
	P[0] = inv[0] = 1;
	for(int i = 1; i < 2 * N; i++)
		P[i] = P[i - 1] * 2 % mod, inv[i] = qpow(P[i], mod - 2);
	cal();
	return 0;
}

启示:如果发现了不用排序的性质,至少能拿到50pts。还是要注重部分分。

D.西安行

一个非常巧妙的转化:\(a^2\)看作在[1,a+1]之间区间的线段上有序选择两个点的方案数。
所以就可以设出状态:\(f_{i,j}\)为走到i,最近的一段里已经放了j个球的方案数。
我们选择刷表法:
\(\large f_{i + 1, 0} = f_{i,0} + f_{i,2}(2断0不断)\)
\(\large f_{i + 1, 1} = 2f_{i,0} + f_{i, 1} + 2f_{i,2}(0不断,两种球;1不断;2断,两种球)\)
\(\large f_{i + 1, 2}=f_{i,0} + f_{i,1} + 2f_{i,2}(0和1不断,2断或不断)\)
这是i为普通点的情况,是黑点就是不能切断,再推一组式子,然后分别搞出来转移使用的矩阵即可。
注意初始化只能\(f_{0,0} = 1\)

启示:组合意义的转化很巧妙。这题暴力DP加前缀和优化也有50pts,还是要关注部分分。

CSP-S模拟赛6

A.跳火山

考虑设\(ans=gcd(x,y)=p\),然后令$x = p * \left \lfloor \frac{b}{p} \right \rfloor $, \(y = p * \left \lfloor \frac{d}{p} \right \rfloor\),这样x和y最靠上,最不容易被a和c卡掉,是正确的。

直接枚举p还是过不了,但是我们发现,如果$\left \lfloor \frac{b}{p} \right \rfloor == \left \lfloor \frac{b}{p+1} \right \rfloor $ 且 $\left \lfloor \frac{d}{p} \right \rfloor == \left \lfloor \frac{d}{p+1} \right \rfloor $,那么可以发现,p+1得出的x和y更大,它一定可行并且优于p。

现在我们需要根据一个满足\(\left \lfloor \frac{b}{p_0} \right \rfloor == \left \lfloor \frac{b}{p} \right \rfloor\)\(p_0\),找到所有\(\left \lfloor \frac{b}{p} \right \rfloor > \left \lfloor \frac{b}{p+1} \right \rfloor\)的p。先算出来\(\left \lfloor \frac{b}{p_0} \right \rfloor\),再用b一除即可。然后每一次,需要在按照b和按照d用这个方式计算出来的右端点中取较小值,然后计算答案。是一个稍微慢于正常的整除分块的东西。

B.赞美太阳

比较令人唏嘘。
首先用哈希来算出来从一条字符串走到另一条的代价,问题类似一个图论问题:在一张有向带权完全图里面走,要至少走m步,求最小代价。m又非常大,这个问题的转移方程又比较容易。所以考虑广义矩阵快速幂,把正常的矩阵乘法里面的乘改成min——+即可。

C.整理

一个原题,但是当时做得一知半解。
数据范围很小,但不是那么小,应该是多项式复杂度,考虑DP。既然是DP,要考虑梳理转移情况。第一种,对于第i组,自己和自己匹配。第二种,两个都和前面的匹配。第三种,一个配前面,一个配后面,注意要乘2,因为题面和数据不同。第四种,两个都配后面。

绝对值,绝对要拆式子。一个如果等着后面的跟它匹配,就贡献负的奇异度。一个如果和前面匹配,就贡献正的奇异度。还有一个性质:对于连续的一段,未匹配的题目和数据应当个数相等。到这里状态已经比较明了了:
\(\large f_{i, j, k}\)为前i个,有j个没匹配,当前奇异度为k(可能为负数)的方案数。
根据状态,写出四个转移方程。注意空间上k那一维要开二倍,因为k可以取负数,要+2500全部变正的。

D.幽邃主教群

这个是套路题,我们使用一个叫树上点边容斥的套路,这条链上亮着的点组成的联通块个数就是亮的点个数减去两头都亮的边条数。我们使用两头中更低的一头来维护边,化边为点。然后丢到权值线段树里面维护即可。两个套路都比较精髓。

posted @ 2025-04-05 21:53  The_Wandering_Earth  阅读(135)  评论(0)    收藏  举报
/