LGR-208-Div.3 做题记录
LGR-208-Div.3 做题记录
vp: \(100 + 100 + 100 + 48 + 0 = 348\)
有的暴力没打。
C. 无穷的迭代器
虽然自己想出来了,但感觉并没有那么显然。
题目可以转化为:对于序列 \(\{x\}\),\(x_0 = 2k + 1\), \(x_i = \dfrac{1}{2}x_{i-1}(x_{i-1}+1)\),求最小的 \(i\) 使得 \(x_i\) 是偶数。
若 \(x_{i-1}\) 是奇数,那么它对于 \(x_i\) 改变奇偶性没有贡献。所以可以构造另一个序列 \(\{x'\}\),\(x'_0 = 2k + 1\),\(x'_i = \dfrac{1}{2}(x'_{i-1}+1)\)(也就是去掉了 \(x_{i-1}\) 这一项)。那么 \(\{x'\}\) 和 \(\{x\}\) 每一项的奇偶性都是相同的,我们用数学归纳法严谨地证明这一点:
基础:当 \(i = 0\) 时,\(x_0 = x'_0\),奇偶性显然相同。归纳:假设 \(x'_{i-1}\) 和 \(x_i\) 奇偶性相同。如果都是奇数,那么
可以看出每一项比起前一项大约都减少了一半,所以暴力计算直到 \(x_i \bmod 2 = 0\) 即可,时间复杂度 \(O(\log k)\)
D. 漫长的小纸带
做题历程:一开始不觉得能 dp,后来试了试 dp 发现可以,写了个暴力 dp 得了 32 pts,稍加优化得到了 48 pts。想到了一些性质感觉可以 A 了,但是没有成功实现代码。看了看题解发现思路是对的,但是我的实现太繁琐了……
首先要看出这题可以 dp。
容易想到 \(O(n^2)\) 的暴力 dp:设 \(f(i)\) 表示前 \(i\) 个数字的最小花费,转移时枚举最后一段的左端点:
其中 \(\operatorname{cost}({j, i})\) 表示 \([j, i]\) 作为一段时的花费。
接下来要做的是发掘性质。显然,答案的上界是 \(n\),因为可以让每个数自成一段。这导出了一个关键结论:每段的元素种类数都不超过 \(\sqrt{n}\),否则单独这一段的花费就超过了 \(n\)。
这启示我们转移时只考虑 \(\sqrt{n}\) 个决策点,换句话说就是枚举这一段的元素种类数,超过 \(\sqrt{n}\) 时停止。实现上可以用 set
来维护每种元素最后出现的位置(注意要先离散化)。
时间复杂度 \(O(n \sqrt{n})\)
vector<int> f(n, INF), lst(n, -1);
set<int> s;
for(int i = 0; i < n; i++)
{
if(lst[a[i]] != -1)
s.erase(lst[a[i]]);
int cnt = 1;
for(auto it = s.rbegin(); it != s.rend(); it++)
{
f[i] = min(f[i], f[*it] + cnt * cnt);
cnt++;
if(cnt * cnt > n)
break;
}
f[i] = min(f[i], cnt * cnt);
lst[a[i]] = i, s.insert(i);
}
总结:
- 没有思路的时候要考虑 dp!有的题乍看上去不能 dp,但实际上可以 dp。尤其是这种段与段之间不影响的,这种性质是利于 dp 的。
- 发掘性质,避免无用决策。
- 想清楚再实现代码。不要搞得太过复杂。
E. 神奇的小江鸟
这真是完全不会了😅
先考虑暴力。找到最短的段,枚举段内的每个数,统计出所有不小于 \(k\) 的因子,作为答案中所有数 \(\gcd\) 的备选值。可以 \(O(1)\) 判断某个区间内是否存在某个数的倍数。
然后想想如何优化。发现目前的瓶颈在于所有的段都可能很长,这会导致备选的因子过多。这里要用到关键结论:如果一个段的长度不小于 \(k\),那么段内一定存在 \(k\) 的倍数。因此如果所有段的长度都不小于 \(k\),那么一定有解。否则枚举因子判断。
总结:没有思路的时候还是得先打暴力,在尝试优化暴力的过程中或许就能有 key obeservation。