AtCoder Grand Contest 047 题解
目前进度:A, B, C, E
现在 AGC 真的越来越不像 AGC 了,还不如 CF 的质量高……连我都上分了质量肯定很低
然而智商低还是得被区分,怎么连 E 的 800 都不会……
这个人已经 sb 到可以犯这种错误了……
A
小数很烦,把每个数变成 \(x\times 10^9\)(小数点后最多 9 位)。
然后原来的两个数乘起来是整数,当且仅当现在的两个数乘起来是 \(10^{18}\) 的倍数。
记录下每个数有多少个 \(2,5\) 作为质因子,然后随便做。
时间复杂度看实现。
B
一眼看上去很 AtCoder 风格,然而完全就是唬人的……
对于一个串 \(S\),会先进行一堆删掉第一个字符的操作(可能零次),也就是删掉一个前缀(可能为空,也可能是全部)。
然后再进行一堆删掉第二个字符的操作(可能零次),也就是第一个字符后面删掉一堆(可能为空,也可能是全部)。
注意到如果接下来再进行删掉第一个字符的操作,完全是白给,本质上仍然是删掉一个前缀。
所以,能被到达的串,一定是一个 \(S\) 的后缀(可能为空),在前面加上这个后缀前面任意一个字符(可以与后缀相邻)。
然后考虑原问题。
首先肯定按长度从大到小排序。直接做不好做,把所有串倒过来。那么判定条件就变成了:一个 \(S\) 的前缀(可能为空),在后面加上这个前缀后面任意一个字符(可以与前缀相邻)。
我们弄一个 Trie,把串一个个插进去。当查询一个串时,先去掉最后一个字符,在 Trie 上跑出节点,然后看子树里有多少个包含最后一个字符的串。
时间复杂度 \(O(|\Sigma|\sum |s_i|)\)。
C
为什么连 AtCoder 都会有这种题了……
考虑对于每个 \(1\) 到 \(P-1\) 的数,算有多少对数的乘积等于它。
先找到 \(P\) 的一个原根(比如 \(2\)),把每个数都表示成 \(2\) 的若干次方。
然后就显然是个循环卷积的形式。
注意要求的是 \(i<j\) 的对,简单魔改一下答案就行了。
时间复杂度 \(O(n+P\log P)\)。
D
虽然还不会,但看起来就是个暴力,先咕着。
E
造计算机题。
把第 \(i\) 个位置设为 \(0/1\)
设为 \(0\) 很简单,随便找个没用过的位置,\(i\) 肯定不小于它,直接赋值。
设为 \(1\) 也不难,随便找个没用过的位置,和 \(a_0+a_1\) 比较。
注意到 \(a_0=a_1=0\) 时,这个操作是造不出 \(1\) 的,但是此时无论怎么操作都不可能造出非零数,所以正确性仍然是有的。
左移 \(k\) 位
把一个数设为它自己加自己,就是乘二。
重复 \(k\) 次即左移 \(k\) 位。
造出任意常数
可以暴力加若干次 \(1\),也可以二进制拆分。
800 分:\(a_0,a_1\le 10\)
我们枚举 \(0\le i,j<10\),如果 \(i<a_0,j<a_1\) 就把 \(a_2\) 加上 \(1\)。
也就是把 \(a_2\) 加上 \(1<((i<a_0)+(j<a_1))\)。(我卡这了……)
操作次数是 \(O(v^2)\)。
二进制拆分
怎么求出一个数的二进制表示并存到一些位置里?
for(z = 29, 28, ..., 0) {
power_of_two = 1 << z;
should_add = (cur + power_of_two < a[i] + 1);
cur += (should_add << z);
a[new_index()] += should_add;
}
操作次数是 \(O(\log^2 V)\)。
原问题
先把两个数拆分。
for(int k = 58; k >= 0; k--) {
answer *= 2;
for(int i = 0; i <= k; i++){
int j = k - i;
if(i < 30 && j < 30) {
answer += 1<(a_bits[i]+b_bits[j]);
}
}
}
操作次数是 \(O(\log^2 V)\)。
F
再说。