T4的题解有误,现已重写.
我们帅童玩家也是站起来了好吧(澄清一下,榜三不是我小号)
报一下个入难度:红 橙 橙/黄 黑蓝 绿 绿.
T1
用 map 记录每个数字出现的次数,然后按题意判断.
T2
每次取出第一个字符放到最后一个,判断是不是回文即可.
string没有pop_front有点烦……
T3
我们可以用一种新型的记录方法,也可以记录到所有的子串.
例如 abcadcbabcadcbabcadcb:
遍历到第 111 个字符,l=1,r=1l=1,r=1l=1,r=1:将 aaa 加入字符串,并增加 111 个子串: aaa.
遍历到第 222 个字符,l=1,r=2l=1,r=2l=1,r=2:将 bbb 加入字符串,并增加 222 个子串:b,abb,abb,ab.
遍历到第 333 个字符,l=1,r=3l=1,r=3l=1,r=3:将 ccc 加入字符串,并增加 333 个子串:c,bc,abcc,bc,abcc,bc,abc.
遍历到第 444 个字符,r=4r=4r=4:由于已经出现过了 aaa,所以第 111 个字符就不能要了,令 l=2l=2l=2. 此时可新增 333 个子串:a,ca,bcaa,ca,bcaa,ca,bca.
遍历到第 555 个字符,l=2,r=5l=2,r=5l=2,r=5:将 ddd 加入字符串,并增加 444 个子串:d,ad,cad,bcadd,ad,cad,bcadd,ad,cad,bcad.
遍历到第 666 个字符,r=6r=6r=6:由于已经出现过了 ccc,所以第 2,32,32,3 个字符就不能要了,令 l=4l=4l=4. 此时可新增 333 个子串:c,dc,adcc,dc,adcc,dc,adc .
遍历到第 777 个字符,l=4,r=7l=4,r=7l=4,r=7:将 bbb 加入字符串,并增加 444 个子串:b,cb,dcb,adcbb,cb,dcb,adcbb,cb,dcb,adcb.
∴\therefore∴ 共有 202020 个不含有重复字符的子串.
翻译成代码如下:
T4
为了方便表示,我将以 xxx 开头,yyy 结尾的子串数量称为 {x,y}\{x,y\}{x,y},数组 aaa 中大于数 xxx 的个数称为 a.LB(x)a.LB(x)a.LB(x),即lower bound.
个人认为本次巅峰赛最难的一题!
认真读题,可发现题目实际让我们找的是如下的代码:
首先,我想到两个块合并只需要把左右两个块的 {x,y}\{x,y\}{x,y} 相加再加上第一个块内 xxx 的数量乘第二个块内 yyy 的数量即可.
于是我轻松地打了个线段树代码:
然后内存爆了.
后来我尝试用分块做,TLE了.
最后我使劲想想想,终于想出来了:
我们不需要维护整个线段树,真正需要维护的只是 676676676 个结果.
我们可以换个角度考虑,如aababbaababbaababb,将第 555 个字符改成 aaa:
先统计负贡献:
1. 在前四个字符与第五个字符的关系中,{a,b}−=3\{a,b\}-=3{a,b}−=3,{b,b}−=1\{b,b\}-=1{b,b}−=1.
2. 在第六个字符与第五个字符的关系中,{b,b}−=1\{b,b\}-=1{b,b}−=1.
再统计正贡献:
1. 在前四个字符与第五个字符的关系中,{a,a}+=3\{a,a\}+=3{a,a}+=3,{b,a}+=1\{b,a\}+=1{b,a}+=1.
2. 在第六个字符与第五个字符的关系中,{a,b}+=1\{a,b\}+=1{a,b}+=1.
我们发现,如果把这个字符串拆开,分为 aaa 字符串与 bbb 字符串:
那么贡献就与 555 在 aaa 字符串与 bbb 字符串的相对位置,即 ∑i∈ba.LB(i)\sum\limits_{i\in b} a.LB(i)i∈b∑ a.LB(i) 有关.
其它的字符串也有这个性质,自行验证.
可以亮代码了……吗?
等等,还有两件事没讲清楚.
1.如何快速求 a.LB(x)a.LB(x)a.LB(x):
如果按正常的数组处理的话,修改时间复杂度就得退化至 O(n)O(n)O(n);
而 setsetset 只会给你返回迭代器,转换成数值又得花费 O(n)O(n)O(n) 的时间.
怎么办呢?
机智的我想到了用树状数组模拟数组!只要每次加入元素在该元素的下标增加 111,删除元素在该元素的下标增加 −1-1−1,那么查询某个下标的结果就是 a.LB(x)a.LB(x)a.LB(x)!
使用这种方法也可以以 O(nlogn)O(n\log n)O(nlogn) 的时间复杂度求得一个数组的逆序对.
2.初始化时间复杂度问题:
确实,通过上面的办法可以让修改变为 O(logn)O(\log n)O(logn),查询变为 O(1)O(1)O(1),但是要初始化. 而如果按照上面的代码初始化,时间复杂度是 O(n2)O(n^2)O(n2)!
没关系,稍微推导一下,就可以推出 {x,y}=∑i∈yx.LB(i)+(i∈x)\{x,y\}=\sum\limits_{i\in y} x.LB(i)+(i\in x){x,y}=i∈y∑ x.LB(i)+(i∈x).
该题代码如下:
T5
模板题,参考区间根号题.
我们发现最多只会运算 350350350 次,所以 O(350n)O(350n)O(350n) 是完全可以的.
具体做法:维护一个线段树,记录区间内 111 的个数,修改时如果发现有一个子树内的元素都为 111 就不搜了;查询直接按普通线段树做.
由于这个算法是自顶而下的,所以就不能用重口味线段树了.
T6
一开始没读题就0帧起手,写了个bfs找环+Floyd算法.
直到我看到了:不会重复经过同一个车站.
天塌了70+行的代码白写了
但是这个提示也带给我了一个好消息:消耗的时间最多也不会超过 151515.
这就让我想到了最短Hamilton路径的解法:状压DP.
巧了,在这题也同样适用!
我们弄个dp,dp[i][j][k]dp[i][j][k]dp[i][j][k] 表示从 iii 出发,第 kkk 个状态,最后一个点为 jjj 是否可能实现.
然后枚举每个时间和所有点,判断当时间为 iii,选取 jjj 点作为车站是否可行.