Atcoder abc268
https://atcoder.jp/contests/abc268/tasks
G - Random Student ID
n个学生 姓名为小写字母,互不相同
问对于所有 a-z 的排列 决定的字典序下
每个学生 的 名字排名顺序期望
范围
名字长度和 5e5
3s
1024mb
我的思路
先估计一下n
1*26+2*26**2+3*26**3+4*26**3*7 = 546234 > 5e5
n < 26+26**2+26**3+26**3*7 = 141310
显然也不能两两计算
感觉可以 基数排序 先计算每个字符串, 的每一位所在的区间大小
而排序 可以看成 首位的期望偏移 + 第二位的期望偏移 + 第三位的期望偏移
可拆!
例如首位是a, 那么 a > b 则有b的长度贡献, a > c 则有c的长度贡献, 而和b与c的大小无关
1 | abcde |
a: (len(b)/2+len(c)/2+len(d)/2+…)
ab: a前缀中 空 + len(a)/2 + len(c)/2 + len(d)/2+…
abc: abc前缀中 空 + len(a)/2 + len(b)/2 + len(d)/2+…
其实就是 前缀中 : 空 + (all-len(cur))/2
注意 为前缀只是长度大小导致的不等关系
似乎就AC了
代码
https://atcoder.jp/contests/abc268/submissions/35779478
1 |
|
Ex - Taboo
给小写字母字符串S, 可以选任意次 修改S中某个字符为星号
目标是,不包含小写字母$T_1\cdots T_N$ 为子字符串(连续的)
问最少需要操作几次
范围
|S| 5e5
|Ti| 长度和 5e5
4s
1024mb
我的思路
其实就是删除多少个,(然后就把字符串切开了)
剩下的都不包含T中的字符串
对于自身不是 自己的前后缀重叠的T来讲, 就是问T的出现次数
而对于自身有 前后缀重叠的, 比如
1 | aba |
就不再是 出现次数了
而, 如果这样去搞 ,似乎得 n^2以上
换个角度, 直接切
dp[i]
表示 第i个切掉, 前面的最小切的次数满足条件
dp[i] = min(dp[j]) + 1, 其中
j < i 且 s[j+1..i-1]
不包含任何T
显然 对于给定i, 那么 有最小的j满足[j+1..i-1]
不包含任何T , 那么 中间的这些也不包含任何T, 所以可选的j是连续的区间
换句话说,j=f(i), dp[i] = min(dp[f(i)..i-1]) + 1
, 这个用数据结构可以快速算出min
如果能快速算出f(i) 就好了
再看 f(i) 显然非严格单调递增, 因为 f(i+1) 显然不小于 f(i),
问题变成 以 i-1 结尾的字符串, 最短出现在t中的长度
因为[f(i-1)..i-1]
相对于 [f(i-1)..i-2]
多出来的全是 s[i-1]
结尾的字符串
一个办法是对t建立字典树, 每次去查, 显然这样 可以达到n^2
感觉需要一些字符串技巧
题解
总览
- 通过把 St1t2…tn拼起来后, 计算 后缀数组SA,和最长公共前缀LCP数组LA
- 计算从 S[i]开始的 最短出现在Ti中的字符串的长度
- 计算最少次数, 让[l1,r1],[l2,r2]… 至少包含一个
*
- 构建 SA和LA
例如对样例, 构建字符串
abcdefghijklmn_abcd_ijk_ghi
然后计算SA和LA
LCP 是一段区间的 LA的值, 可以segtree上求
- 计算多少个
字符
从S[i]开始和Tj重复
其实就是在SA以后
1 | Tj......_ |
换句话说 区间 sa[Tj..si] 这一段的最大公共长度应该大于等于Tj的长度
现在要找最小的长度
反过来, 通过tj 去找
对tj, 通过二分找 最大的位置 公共长度大于等于 |tj|, 这样 这一段sa 的min len 都等于|tj|
就是个线段树计算区间min(SA的min) + 二分搜索 + 线段树维护区间min(|tj|的min)
需要注意的是拼接,可能出现如下的情况
……..xxx#xxx#???
这样 去算SA会有问题
Ti开始的 xxx#??? 会大于S末尾的xxx#xxx#???
这样找区间会有未覆盖的S的
一个办法就是 s后面是’a’-1, t后面接’a’-2, 这样保证t如果是s前缀,则一定在s前面
最后就是一个倒着的dp 和我上面想得一样
代码
179行 1900ms
https://atcoder.jp/contests/abc268/submissions/35787022
1 |
|
总结
G
没啥难的, 注意到期望可拆就行
Ex
后缀数组 SA
恩 后缀数组还是不熟, 其实应该想到dp的思路的话 正向反向是对称的
所以既然正向想到求一个位置向前字符串, 那么其实反过来就应该想到从一个位置开始向后的字符串了! 那么就自然到后缀数组了