目前进度:A, B, C, E
现在 AGC 真的越来越不像 AGC 了,还不如 CF 的质量高……连我都上分了质量肯定很低
然而智商低还是得被区分,怎么连 E 的 800 都不会……
这个人已经 sb 到可以犯这种错误了……
A
小数很烦,把每个数变成 (x imes 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+Plog 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_1le 10)
我们枚举 (0le 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
再说。