AGC047 解题报告
A Integer Product
给定 \(n\) 个浮点数 \(a_i\) ,问有多少组数对 \((i,j)\) 满足 \(a_i\times a_j\) 是整数 。
\(n\le 2\times 10^5\) , \(a_i\) 小数点后只有不超过 \(9\) 位数 。
这是一道套路的签到题。
小数相乘变为整数很容易想到计算 \(2\) 和 \(5\) 的个数,那么对于 \(a_i\) 和 \(a_j\) ,先将两者都乘上 \(10^9\) ,然后分别统计质因数中 \(2\) 和 \(5\) 的幂次,如果两者的 \(2\) 和 \(5\) 的幂次分别求和的最小值大于 \(18\) ,那么两者相乘就是整数。
由于数据比较小,可以直接上二维前缀和统计答案,比较好写。
有一个坑点,如果你是用小数读入然后乘上 \(10^9\) 的话,会因为精度丢失只有 \(40\) 分,所以要使用 \(llround\) 或者字符串读入。
B First Second
给定 \(n\) 个串 \(S_i\) ,定义对串 \(T\) 的一次变换为删掉 \(T\) 的第一个或第二个字符,问有多少个二元组 \((i,j)\) 满足能够通过对 \(S_i\) 进行若干次变换使得其等于 \(S_j\) 。
\(n\le 2\times 10^5 , \sum\limits |S_i|\le 10^6\) 。
一个很套路的字符串题。
观察有贡献的条件,发现只要有一个字符串删去第一个字符是另一个字符串的后缀,且第一个字符在另一个字符串除去那个后缀依然有出现过,就算满足条件。
套路的建立字典树,然后在每个节点上维护一下就行。
C Product Modulo
给定 \(n\) 个非负整数 \(a_i\) ,求出 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n ((a_i\times a_j)\% 200\ 003)\) 的值。
\(200\ 003\) 是一个质数, \(n\le 10^5 , 0\le a_i\le 200\ 003\) 。
发现模数很小,可以考虑统计两数乘积取模的个数。
有一个有用的技巧,可以利用原根将乘法转加法。
\(200\ 003\) 的原根为 \(2\) ,那么 \(2^i\ \%200\ 003\ (0\le i\le 200\ 001)\) 就会不重不漏地包含 \(1-200\ 002\) 的所有数,可以用一个 \(F(x)\) 表示模数为 \(2^x\%200\ 003\) 的数的个数。
因为 \(2^i\times 2^j=2^{i+j}\) ,所以有 \(Ans(x)=\sum\limits_{i+j=x}F(i)\times F(j)\) ,那么 \(F(x)\) 自己和自己的卷积就是答案了。
注意去重问题和用 \(FFT\) 。
D Twin Binary Trees
有两棵点数同为 \(n\) 的满二叉树,第一棵树的第 \(i\) 个叶节点向第二棵树的第 \(A_i\) 个节点连了一条特殊边。
在所有边构成的图上,一个环是合法的,当且仅当它是简单环,并且恰好经过两条特殊边。
定义一个合法环的权值为它所经过的所有点的编号的乘积。
求所有简单环的权值之和对 \(10^9+7\) 取模的值。
\(n<2^{18}\) 。
大力题。
由于是个完全二叉树,很容易想到可以暴力跳祖先,然后随便怎么大力搞一搞就行。
这里提供一种十分无脑的做法。
考虑对上面的树类似分治,然后在在下面那棵树对应的节点建立虚树,暴力跳祖先维护答案,效率 \(\mathcal{O(n\log^2 n)}\) 。
E Product Simulation
有一个序列 \(a_0, a_1, ⋯, a_n\) ,初始时 \(a_0=A, a_1=B; a_2=a_3=⋯=a_n=0\)
你可以执行至多 \(q\) 次操作,每次操作有两种:
+ i j k
:令 \(a_k=a_i+a_j\)
< i j k
:令 \(a_k=[a_i<a_j]\)你需要构造一种操作序列使得,无论 \(A,B\) 是任何非负整数,执行完所有操作后 \(a_2=A\times B\)
\(n=q=2\times 10^5 , A,B\in [0, 10^9]\)
比较套路的提交答案题。
由于操作只有加法和比大小,变成乘法只能用龟速乘,也就是类似快速幂一样处理乘法,预处理出 \(a_0\times 2^i\) 。
考虑如何解决加上 \(a_0\times 2^i\) 时是否会超出 \(a_0\times a_1\) 的问题,可以转换为求解 \(a_0\) 只为 \(0\) 或 \(1\) 时的情况。
依然考虑使用二进制拆分,对于 \(a_1\) 的每一位进行求解,那么就可以转化为一个更好解决的 \(a_0\) 和 \(a_1\) 都只为 \(0\) 或 \(1\) 时的子问题。
显然此时答案只用将 \(a_0\) 和 \(a_1\) 加起来再和 \(1\) 进行比较就行, \(1\) 可以靠 \([a_0>a_1]+[a_1>a_0]\) 来取得。
实际上这题就是二进制拆分的 \(trick\) 套两次,操作数是 \(\mathcal{O(\log^2 n)}\) 。
是不是提答和交互都喜欢考二进制拆分和分治啊(
F Rooks
一个无限大的棋盘上有 \(n\) 个『車』,第 \(i\) 个『車』的位置在 \((X_i,Y_i)\) ,可以攻击到在同一横排或纵排的位置,数据保证『車』两两之间不会相互攻击到。
可以选择一个『車』将其换成『将』,『將』可以在竖直和水平方向走动以及斜对角吃掉『車』(可以看作一个超级『卒』),要求『將』不能走到任意一个『車』的攻击范围内。
现在请求出将任意一个『車』替换为『將』时,在吃掉最多的『車』的情况下需要的最小步数是多少。
\(2\le n\le 200\ 000 , 1\le X_i,Y_i\le 10^6\)
不套路但思路比较好想的性质题。
先考虑将一个车替换为王后能吃掉哪些车,可以发现如果按照每一个车的 \((X_i,Y_i)\) 画出两条垂直且经过该点的线,然后划分出许多的方格,一个点能吃掉另外一个点的条件就是这两个点都在一个单位方格的两个相对的角上,那么可以相互吃到的车一定在同一个矩形里,大致像这样:
蓝色框内的点意味着它们能相互之间吃到,单个点意味着它无法吃到其他的点。
这样就可以划分为许多的矩形分开计算,每个矩形都将能相互吃到的车划在一起。
根据这样的划分方法,可以发现一些性质,一个矩形内的点一定是单调的,一个矩形中的点如果从内到外一定是一个矩形不断套上一个矩形形成的,且每个矩形上的点只会是有对角的两个点或单独一个点。
可以先选择一个方块再在外面讨论如何加点就可以证明上面的性质。
所以就会出现下面的情形:
我们先考虑对于某个确定的点如何求出答案,由于蓝色框中的点都是单调的,所以一个点要吃到另外一个点,要走的距离是两点的哈曼顿距离减一,总距离就是蓝框相对点的哈曼吨距离减去点数加一,一个矩阵中就会是这样的蓝框交替存在,根据观察发现一定是从内走外走完这个蓝框的点后再到另外一边的对角清除这几层外套的矩阵,每次只需要选择是先吃哪个角上的蓝框再到另外一个角吃掉那边的蓝框,这样就可以清除这个矩阵的限制到下一个矩阵,这个可以使用dp解决。
但是我们要求出所有点的答案,那又要怎么做呢?实际上可以发现,对于一个像这样套起来的矩阵,只有中间的那个会遍历完全部,其他的点都只能吃到所属蓝框里的点,而且这样套起来的矩阵两两之间最多有一个蓝框是重叠的,所以对于每个这样的套起来的矩阵都dp一次,总效率是 \(\mathcal{O(n)}\) 的。
感觉细节会很多。
DEF均为自己口胡,讲的可能不是很清楚。
目前DEF的代码都还没有写,大概noip考完会补上吧。
话说这场比赛的思维量不高啊,倒是代码的细节有点多(