cout << "Hello World!" << endl;|

xzm111

园龄:2年粉丝:1关注:0

Codeforces Round 924 (Div. 2)

E - Modular Sequence

题意

给定 n,x,y,s,求是否有长为 n 的一个数列 {a} 满足 a1=xi>1:ai=ai1+yai=ai1modyi=1nai=s

n,s2×105

题解

观察到对任意的 i 都有 aix(mody),于是可以先给 s 减去 n×(xmody),剩下的部分一定是非负的 y 的倍数,否则显然不合法。

c=sn×(xmody)y,c0=xy,于是问题转化为:求一个数列 b 满足第一项为 c0,和为 c,每一项要么等于前一项加一,要么为 0(这相当于若干个公差为 1 的等差数列拼起来)。

直接考虑每个位置做 DP 最少也要 2D 的状态(位置,上一个的值),但是观察到值域很小,于是不妨交换状态和答案,设 dpi 表示得到和为 i 的数列 b 需要的最小长度。由于可以在后面补 0,所以有解的充要条件为 dpcn

转移考虑枚举下一个等差数列的长度,若当前计算 dpi,枚举的长度为 j,则显然需要满足 ij(j1)2,于是有 jO(i),那么暴力转移即可做到 O(ss)

由于第一个等差数列的首项比较特别,但是仅有它一个特别的,于是先暴力枚举它的长度给 dp 数组赋初值即可。

于是处理一组数据的时间复杂度为 O(n+ss)

Submission

F - Digital Patterns

题意

给定 a1,a2,,anb1,b2,,bn,构造 nm 列的矩阵满足 (i,j) 处的值为 ai+bj。定义答案为满足方阵中任意一条边两侧的数不同的子方阵个数。每次修改是对 ab 中的一段区间加 x,求每次修改后和最初时的答案。

题解

首先考虑不带修怎么求。观察到 (i,j) 处和 (i,j+1) 处值相同的充要条件为 bj=bj+1(i,j)(i+1,j) 同理,于是相当于在相邻且相同的两行中间切开,相邻且相同的两列中间切开,对得到的若干子矩阵求答案并求和。

文字有点抽象,可以看样例:

image

f(n,m) 表示 n×m 矩阵的子方阵数目,则样例 1 的答案为 f(1,2)+f(1,2)+f(3,2)+f(3,2)

考虑如何计算 f,容易枚举方阵大小计算,不失一般性,设 nm

f(n,m)=i=1n(ni+1)(mi+1)

这个式子显然不好弄,我们需要更好算的式子,容易发现它是一个三次多项式,可以大力展开:

f(n,m)=i=1n(ni+1)(mi+1)=i=1ni(mn+i)=i=1n(mn)i+i2=(mn)(i=1ni)+(i=1ni2)=(mn)n(n+1)2+n(n+1)(2n+1)6=mn2+n2+n3+n6

这个式子已经很简洁了。注意到只要对 n,m 的大小分类讨论,并维护出它们对应的 03 次和就可以快速对一个固定的 m 求出 if(ni,m),固定的 n 同理。

于是可以先对行列分别按相等位置分段,对值域开数据结构维护一个方向的长度的 03 次和,并依次添加另一个方向的长度,同时计算答案即可。

对于修改,首先发现区间修改是骗人的,因为我们关注的只是相邻元素是否相同,于是区间修改相当于改变左右端点处的相等情况,相当于对相等情况的两次单点改。

单点改可以等价于先删再加,删除和添加都可以根据上面的式子讨论大小关系后求出答案变化量。删除和添加的区间长度容易用 set 维护。

至此我们得到了一个常数巨大的 O(nlogn+qlogn) 的做法,写得一般的线段树好像还过不了(zkw 可过),不过 03 次和可以用 8 个 BIT 分别维护,区间加可以用两个 BIT 维护差分(只有单点查),这里 set 因为操作少所以还不算瓶颈。

Submission

本文作者:Transparent

本文链接:https://www.cnblogs.com/xzmxzm/p/18013609/CF1928

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xzm111  阅读(64)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起