CF557E Ann and Half-Palindrome 题解
算法:dp+字典树
在CF刷字符串题的时候遇到了这题,其实并没有黑题这么难,个人感觉最多是紫题吧(虽然一开始以为是后缀自动机的神仙题)。
首先注意到字符串 \(s\) 长度很小( \(1\le|s|\le5000\) ),可以 \(\mathcal O(n^2)\) 地把所有子串求出来,再用Trie树存起来,这样就方便我们dfs求字典序第 \(k\) 小的半回文串。所以问题重心变为怎么快速判断这些子串是否为半回文串。根据半回文串的特点,长度长的半回文串是包含长度小的半回文串的,所以我们可以用区间dp解决。设 \(f[i][l]\) 表示 \(s[i,i+l-1]\) 是否为半回文串,它的转移方程可以写作( \([A]\) 表示 \(A\) 为真时值为1,否则为0):
\]
这样dp的时间复杂度也是 \(\mathcal O(n^2)\) 的。之后dfs求解第 \(k\) 小的半回文串就比较简单了,由于Trie节点数也是 \(\mathcal O(n^2)\) 的,所以总时间复杂度是 \(\mathcal O(n^2)\) 的。
\(Code:\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e3 + 5;
bool f[N][N];
int trie[N * N][2],cnt,num[N * N],tot,k;
char s[N+6],ans[N];
void dfs(int now){
for(int i = 0;i <= 1;i++){
int next = trie[now][i];
if(next == 0) continue;
//如果该节点所表示的半回文串数量大于k,说明答案就是该半回文串。
if(k <= num[next]) {
ans[++tot] = i + 'a';
for(int j = 1; j <= tot; j++) printf("%c", ans[j]);
exit(0);
}
k -= num[next]; //k为全局变量
ans[++tot] = i + 'a';
dfs(next);
tot--;
}
}
int main() {
scanf("%s %d",s+1,&k);
int len = strlen(s+1);
for(int i = 1;i <=len;i++) f[i][1] = 1;
for(int i = 1;i < len;i++) f[i][2] = s[i] == s[i+1];
for(int i = 1;i < len;i++) f[i][3] = s[i] == s[i+2];
for(int i = 1;i < len;i++) f[i][4] = s[i] == s[i+3];
for(int l = 5;l <= len;l++)
for(int i = 1; i <= len; i++)
f[i][l] = (s[i] == s[i+l-1] && f[i+2][l-4]);
//将s所有子串加入trie树中
for(int i = 1;i <= len;i++){
int now = 0;
for(int l = 1; l+i-1 <= len; l++){
int c = s[i+l-1] - 'a';
if(trie[now][c] == 0) trie[now][c] = ++cnt;
now = trie[now][c];
if(f[i][l]) num[now]++;
}
}
dfs(0);
return 0;
}
CF557E Ann and Half-Palindrome 题解的更多相关文章
- POJ3974:Palindrome——题解
http://poj.org/problem?id=3974 题目大意: 求最大回文子串长度. ———————————————————— 马拉车板子题. 马拉车大概讲解: 首先在每两个字母之间插入‘# ...
- URAL1297:Palindrome——题解
http://acm.timus.ru/problem.aspx?space=1&num=1297 https://vjudge.net/problem/URAL-1297 给定一个字符串,求 ...
- CF557E Ann and Half-Palindrome 字典树+dp
现在看这道题也不难啊,不知道考场上为啥没切~ code: #include <bits/stdc++.h> #define N 5006 #define setIO(s) freopen( ...
- Valid Palindrome leetcode java
题目: Given a string, determine if it is a palindrome, considering only alphanumeric characters and ig ...
- 【leetcode刷题笔记】Valid Palindrome
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...
- Leetcode 9. Palindrome Number(水)
9. Palindrome Number Easy Determine whether an integer is a palindrome. An integer is a palindrome w ...
- 2013-2014集训之DP
第一周: 经过漫长的时间,终于有时间来写一下结题报告. 地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=36180#overview A ...
- A. Karen and Morning
A. Karen and Morning time limit per test 2 seconds memory limit per test 512 megabytes input standa ...
- [置顶] 刘汝佳《训练指南》动态规划::Beginner (25题)解题报告汇总
本文出自 http://blog.csdn.net/shuangde800 刘汝佳<算法竞赛入门经典-训练指南>的动态规划部分的习题Beginner 打开 这个专题一共有25题,刷完 ...
随机推荐
- Chapter Zero 0.2.3 显示适配器
显示适配器(Video Graphics Array,VGA) 不看后悔!!深入了解显卡!!!走你! 我们常常会调试显示器的分辨率,一般对于图像的显示重点在于分辨率与颜色深度, 每个图像显示的颜色会占 ...
- Linux CentOS7.x 升级内核的方法
一.概述 在数据中心基础环境中,Linux系统使用很普遍,但是有时候会遇到应用程序需要运行在高版本的内核上或者有时候系统自身要求需要升级内核,我们要综合考虑升级内核的风险. 二.升级内核的方法 1.查 ...
- KafkaConsumer 简析
使用方式 创建一个 KafkaConsumer 对象订阅主题并开始接收消息: Properties properties = new Properties(); properties.setPrope ...
- Leetcode(198)-打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个代表每 ...
- js code review
js code review https://codereview.stackexchange.com/ refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只 ...
- vue & this.$copyText
vue & this.$copyText click copy https://www.npmjs.com/package/vue-clipboard2 <p>{{message2 ...
- IoT & Raspberry Pi
IoT & Raspberry Pi https://www.raspberrypi.org/ https://www.raspberrypi.org/training https://pro ...
- Rollup & Webpack & Parcel
Rollup & Webpack & Parcel package bundler https://x-team.com/blog/rollup-webpack-parcel-comp ...
- js 创建XML
// 创建xml数据 let doc = document.implementation.createDocument('', 'root', null); // 创建一个文档 let root =d ...
- VAST上线后,如何提升NGK算力生态的收益和流动性?
自比特币诞生以来,"挖矿"一词就成功地步入了大众的视野,也成为了加密货币领域最重要的组成部分之一.无论是早前基于比特币和以太坊为主的算力挖矿,还是逐步进入大众视野的质押挖矿,亦或是 ...