\(1\) LG1659 [国家集训队]拉拉队排练

求前\(k\)大的奇数长度回文串的长度之积。

\(\rm |S|\leq 1e6,K\leq 1e12\)

……一开始觉得挺水,就开始二分最少长度能到多少。写写写…写到最后发现细节很烦人…然后最后发现是错的qaq

二分是没错,只是最后计算错了。大概就是考虑二分出的最小长度是\(k\),对于一个大于\(k\)的长度\(l\)有好多个,没法知道\(l\)们到底要算到几,也就是说\(7\)中一定包含着\(3/5/7\),但是对于\(l\),其中可能有拆出\(7,5\)来的,也有可能有拆出\(7,5,3\)来的,无法同一个长度一起算。

以下是错误代码:

int ns[MAXN], base[MAXN], buc[MAXN], ed[MAXN] ;
int N, L = -1 ; LL K, res, fact = 1, _up ; char In[MAXN] ; il LL expow(LL x, LL y){
LL ret = 1 ;
while (y){
if (y & 1)
(ret *= x) %= Mod ;
(x *= x) %= Mod, y >>= 1 ;
}
return ret ;
}
il bool check(int p){
LL ret = 0 ;
int x = ed[p], i ;
if (x % 2 == 0) return 0 ;
for (int i = 1 ; i < p ; ++ i)
ret += 1ll * ((ed[i] - ed[p] + 2) / 2) * 1ll * buc[ed[i]] ;
return (bool)(ret + (buc[ed[p]]) >= K) ;
}
int main(){
cin >> N >> K >> (In + 1) ;
ns[++ L] = '$', ns[++ L] = '#' ; int id = 0, rt = 0 ;
for (int i = 1 ; i <= N ; ++ i) ns[++ L] = (int)In[i], ns[++ L] = '#' ;
for (int i = 1 ; i <= L ; ++ i){
if (rt <= i) base[i] = 1 ;
else base[i] = min(base[2 * id - i], rt - i + 1) ;
while (ns[i - base[i]] == ns[i + base[i]]) ++ base[i] ;
if (rt <= i + base[i] - 1) rt = i + base[i] - 1, id = i ;
}
for (int i = 1 ; i <= 2 * N + 2 ; ++ i) buc[base[i] - 1] ++ ;
for (int i = 1 ; i < MAXN ; i += 2) if (buc[i]) ed[++ tot] = i ;
reverse(ed + 1, ed + tot + 1) ; int L = 1, R = tot, Mid, ans, pos = 0 ;
while (L <= R){
Mid = (L + R) >> 1 ;
/*if (rand() % 2)
while (ed[Mid] % 2 == 0 && Mid < R) ++ Mid ;
else
while (ed[Mid] % 2 == 0 && Mid > L) -- Mid ;*/
if (check(Mid)) ans = Mid, R = Mid - 1 ; else L = Mid + 1 ;
}
pos = ans, res = 1ll, _up = ed[1] ;
for (int i = ed[pos] ; i <= ed[1] ; i += 2) fact *= 1ll * i ;
for (int i = 1 ; i <= pos ; ++ i){
while (ed[i] < _up) fact /= _up, _up -= 2 ;
if ((ed[i] - ed[pos] + 2) / 2 > K){
int j = 0 ;
while (ed[i] >= ed[pos] && j < K)
res = res * 1ll * ed[i], ed[i] -= 2, ++ j ;
break ;
}
res = res * expow(fact, buc[ed[i]] <= K ? buc[ed[i]] : K) % Mod ;
K -= 1ll * ((ed[i] - ed[pos] + 2) / 2) * 1ll * buc[ed[i]] ;
if (K <= 0) break ;
}
cout << res << endl ; return 0 ;
}

观察失误点,贡献无法提前计算,那么可以考虑延后计算,这样一定能保证准确凑出来\(K\).

int tot, ns[MAXN], base[MAXN], buc[MAXN], ed[MAXN] ;
int N, L ; LL K, res, fact = 1, _up ; char In[MAXN] ; il LL expow(LL x, LL y){
LL ret = 1 ;
while (y){
if (y & 1)
(ret *= x) %= Mod ;
(x *= x) %= Mod, y >>= 1 ;
}
return ret ;
}
int main(){
cin >> N >> K >> (In + 1) ;
ns[++ L] = '$', ns[++ L] = '#' ; int id = 0, rt = 0 ;
for (int i = 1 ; i <= N ; ++ i) ns[++ L] = (int)In[i], ns[++ L] = '#' ;
for (int i = 1 ; i <= L ; ++ i){
if (rt <= i) base[i] = 1 ;
else base[i] = min(base[2 * id - i], rt - i) ;
while (ns[i - base[i]] == ns[i + base[i]] && i + base[i] <= L && i - base[i] >= 1) ++ base[i] ;
if (rt <= i + base[i] - 1) rt = i + base[i], id = i ;
}
for (int i = N ; i >= 1 ; -- i){
ans += buc[i] ;
if (!(i & 1)) continue ;
if (ans <= K)
(res *= expow(i, ans)) %= Mod, K -= ans ;
else { (res *= expow(i, K)) %= Mod, K -= ans ; break ; }
}
cout << res << endl ;
return 0 ;
}

。。。这题一开始写挂了,然后两天后(就是写这行字的时候)整理这道题,又调了半天才发现为啥二分不对…qaq脑子是个好东西。

\(2\) LG4555 [国家集训队]最长双回文串

这题比第一题友善了很多。。。

输入长度为\(n\)的串\(S\),求\(S\)的最长双回文子串\(T\),即可将\(T\)分为两部分\(X\),\(Y\),(\(|X|,|Y|≥1\))且\(X\)和\(Y\)都是回文串。

嗯,其实就是求以每个点为右端点/左端点的最长回文串长度。用Manacher做的话,就是一开始先推出以每个点为轴的最长回文串长度,然后用这个去更新每端点。注意到这么做有些包含在原来求出的最长回文串内部的小回文串可能并不可以求出来,于是再dp一遍即可。

	cin >> (In + 1), N = strlen(In + 1) ;
int i, id = 0, rt = 0 ; ns[++ L] = '$', ns[++ L] = '#' ;
for (i = 1 ; i <= N ; ++ i) ns[++ L] = (int)In[i], ns[++ L] = '#' ;
for (i = 1 ; i <= L ; ++ i){
if (rt <= i) base[i] = 1 ;
else base[i] = min(rt - i + 1, base[2 * id - i]) ;
while (ns[i + base[i]] == ns[i - base[i]]) base[i] ++ ;
if (i + base[i] > rt) rt = i + base[i] - 1, id = i ;
}
// for (i = 1 ; i <= L ; ++ i) cout << base[i] << " " ; puts("") ;
// for (i = 1 ; i <= L ; ++ i) cout << (char)ns[i] << " " ;
for (i = 1 ; i <= L ; ++ i){
int l = i / 2 - (base[i] / 2) + 1 ;
int r = i / 2 + (base[i] / 2) - 1 ; if (ns[i] == 35) ++ r ;
Ls[r] = max(Ls[r], base[i] - 1), Rs[l] = max(Rs[l], base[i] - 1) ;
}
for (i = 1 ; i <= N ; ++ i) Ls[i] = max(Ls[i], Ls[i + 1] - 2) ;
for (i = 1 ; i <= N ; ++ i) Rs[i] = max(Rs[i], Rs[i - 1] - 2) ;
// for (i = 1 ; i <= N ; ++ i) cout << Ls[i] << " " ; puts("") ;
// for (i = 1 ; i <= N ; ++ i) cout << Rs[i] << " " ;
for (i = 1 ; i < N ; ++ i) ans = max(ans, Ls[i] + Rs[i + 1]) ; cout << ans << endl ; return 0 ;
}

[题解向] Manacher简单习题的更多相关文章

  1. [题解向] PAM简单习题

    \(1\) LG5496 [模板]回文自动机 对于 \(s\) 的每个位置,请求出以该位置结尾的回文子串个数. \(|s|\leq 1e6\) 然后就是PAM的板子题咋感觉好像没有不是很板的PAM题呢 ...

  2. [题解][YZOJ50104] 密码 | 简单计数

    同步发表于 Mina! 题目大意 对于满足以下要求的长度为 \(n\) 的序列进行计数: 序列的值域为 \([1,k]\); 对于序列的任意位置 \(p\in[1,n]\),可以找到至少一个 \(i\ ...

  3. python学习日记(2/3区别,环境,变量,数据类型以及简单习题)

    Python2 与 python3 的区别: python2源码不标准,混乱,重复代码太多 python3统一标准,去除重复代码 python2的默认编码方式是ASCII码,不能识别中文.解决方法:在 ...

  4. Leetcode题解 - DFS部分简单题目代码+思路(113、114、116、117、1020、494、576、688)

    这次接触到记忆化DFS,不过还需要多加练习 113. 路径总和 II - (根到叶子结点相关信息记录) """ 思路: 本题 = 根到叶子结点的路径记录 + 根到叶子结点 ...

  5. Leetcode题解 - 树部分简单题目代码+思路(105、106、109、112、897、257、872、226、235、129)

    树的题目中递归用的比较多(但是递归是真难弄 我

  6. 关于java基础_方法的简单习题

    package day05; import java.util.Arrays; /** * 方法作业 * @author ASUS * */ public class Demo6 { /* * 1.定 ...

  7. HDU 4513 吉哥系列故事——完美队形II (Manacher变形)

    题意:假设有n个人按顺序的身高分别是h[1], h[2] ... h[n],从中挑出一些人形成一个新的队形,新的队形若满足以下要求,则就是新的完美队形:  1.连续的 2.形成回文串 3.从左到中间那 ...

  8. 《ACM国际大学生程序设计竞赛题解Ⅰ》——基础编程题

    这个专栏开始介绍一些<ACM国际大学生程序设计竞赛题解>上的竞赛题目,读者可以配合zju/poj/uva的在线测评系统提交代码(今天zoj貌似崩了). 其实看书名也能看出来这本书的思路,就 ...

  9. 最长回文(Manacher)

    HOT~ 杭电2015级新生如何加入ACM集训队? 最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

随机推荐

  1. 利用openssl自建CA体系

    使用 OpenSSL 创建私有 CA:1 根证书 使用 OpenSSL 创建私有 CA:2 中间证书 使用 OpenSSL 创建私有 CA:3 用户证书 今天跟着上面的三部曲,做了一下openssl的 ...

  2. SCTF2019 Crypto-warmup writeup

    题外话 其实这道题在比赛过程中并没有解出来,思路完全想偏导致无解就放弃了,后来研究了大佬的writeup大半天才看懂... 正文 nc获取题目信息,返回一段明文和密文,要求输入一段明文和密文. 题目源 ...

  3. Win10锁屏壁纸位置

    C:\Users\MIS\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalStat ...

  4. [洛谷P1169][题解][ZJOI2007]午餐

    这是题目吗? 显然的DP,讲几个重要的地方 1.贪心:让吃饭时间长的先排队(证明从略) 2.状态: f[i][j][k]代表前i个人,一号时间j,二号时间k显然MLE 所以压缩成f[i][j]代表前i ...

  5. [专题总结]初探插头dp

    彻彻底底写到自闭的一个专题. 就是大型分类讨论,压行+宏定义很有优势. 常用滚动数组+哈希表+位运算.当然还有轮廓线. Formula 1: 经过所有格子的哈密顿回路数. 每个非障碍点必须有且仅有2个 ...

  6. dotnet core 调用electron来开发UI的探索

    先上仓库地址 https://github.com/lightszero/webwindow.netcore dotnet core 很喜欢,问题dotnet core 不包含GUI,经过一些尝试,觉 ...

  7. Elasticsearch索引按月划分以及获取所有索引数据

    项目中数据库根据月份水平划分,由于没有用数据库中间件,没办法一下查询所有订单信息,所有用Elasticsearch做订单检索. Elasticsearch索引和数据库分片同步,也是根据月份来建立索引. ...

  8. Python 周刊第 418 期

    新闻 PyCon US 2020 开始接受财务赞助! https://pycon.blogspot.com/2019/10/financial-aid-launches-for-pycon-us-20 ...

  9. Python的生成器和生成器表达式

    一,生成器和生成器表达式 什么是生成器,生成器实质就是迭代器,在python中有三种方式来获取生成器: 1. 通过生成器函数 和普通函数没有区别,里面有yield的函数就是生成器函数,生成器函数在执行 ...

  10. go语言之用户输入&类型别名&类型转换

    1.用户输入 package main import "fmt" func main() { //用户输入,程序接受并输出 var v1 int //fmt.Println(&qu ...