Codeforces Round #311 (Div. 2) E - Ann and Half-Palindrome(字典树+dp)
1.5 seconds
512 megabytes
standard input
standard output
Tomorrow Ann takes the hardest exam of programming where she should get an excellent mark.
On the last theoretical class the teacher introduced the notion of a half-palindrome.
String t is a half-palindrome, if for all the odd positions i (
)
the following condition is held: ti = t|t| - i + 1,
where |t| is the length of string tif
positions are indexed from 1. For example, strings "abaa",
"a", "bb", "abbbaa"
are half-palindromes and strings "ab", "bba"
and "aaabaa" are not.
Ann knows that on the exam she will get string s, consisting only of letters a and b,
and number k. To get an excellent mark she has to find the k-th
in the lexicographical order string among all substrings of s that are half-palyndromes. Note that each substring in this order is
considered as many times as many times it occurs in s.
The teachers guarantees that the given number k doesn't exceed the number of substrings of the given string that are half-palindromes.
Can you cope with this problem?
The first line of the input contains string s (1 ≤ |s| ≤ 5000),
consisting only of characters 'a' and 'b',
where |s| is the length of string s.
The second line contains a positive integer k — the lexicographical number of the requested string among all the half-palindrome substrings
of the given string s. The strings are numbered starting from one.
It is guaranteed that number k doesn't exceed the number of substrings of the given string that are half-palindromes.
Print a substring of the given string that is the k-th in the lexicographical order of all substrings of the given string that are
half-palindromes.
abbabaab
7
abaa
aaaaa
10
aaa
bbaabb
13
bbaabb
By definition, string a = a1a2... an is
lexicographically less than string b = b1b2... bm,
if either a is a prefix of b and
doesn't coincide withb, or there exists such i,
that a1 = b1, a2 = b2, ... ai - 1 = bi - 1, ai < bi.
In the first sample half-palindrome substrings are the following strings — a, a, a, a, aa, aba, abaa, abba, abbabaa, b, b, b, b, baab,bab, bb, bbab, bbabaab (the
list is given in the lexicographical order).
http://codeforces.com/contest/557/problem/E
大致题意:找出s的子串中字典序第k小的“半回文串”,给出半回文串定义是:对于随意i<=|s|/2 有s[i] = s[len-i+1]
数据量是5000
O(n^2)的算法可行
简单暴力的方法就是n^2 dp 出(i,j)的子串是不是半回文串,再把全部子串插入字典树。在dfs遍历出第k小的串
方法二,dp[i][j]统计出以i为始端到i~j的子串是回文串的总数。再把全部子串插入字典树,然后二分出答案子串。
方法一:
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
using namespace std;
typedef long long ll; const int N = 5000+5;
int dp[N][N];
char s[N];
int k;
int n;
struct node
{
node *son[2];
int cnt;
node()
{
memset(son,0,sizeof(son));
cnt = 0;
}
}trie[N*N];
int SZ = 0;
node *root,*cur;
node *createnode()
{
return &trie[SZ++];
}
void Insert(int p)
{
cur = root;
for(int i = p;i <= n;i++)
{
int val = s[i]-'a';
if(cur->son[val] == NULL) cur->son[val] = createnode();
cur = cur->son[val];
cur->cnt += dp[p][i];
}
}
int getsum(node *cur)
{
int sum = 0;
if(cur->son[0]) sum += getsum(cur->son[0]);
if(cur->son[1]) sum += getsum(cur->son[1]);
cur->cnt += sum;
return cur->cnt;
}
vector<char>ans;
bool dfs(node *cur,int &k)
{
if( k <= 0) return true;
if(cur->son[0])
{
ans.push_back('a');
if(cur->son[0]->cnt) k -= cur->son[0]->cnt;
if(dfs(cur->son[0],k)) return true;
ans.pop_back();
}
if(cur->son[1])
{
ans.push_back('b');
if(cur->son[1]->cnt)k -= cur->son[1]->cnt;
if(dfs(cur->son[1],k)) return true;
ans.pop_back();
}
return false;
}
int main()
{
scanf("%s%d",s+1,&k);
n = strlen(s+1);
for(int i =0;i <= n+2;i++)
for(int j = i;j >= 0;j--)
dp[i][j] = 1;
for(int len = 2;len <= n;len++)
for(int l = 1;l+len-1 <= n;l++)
{
int r = l+len-1;
dp[l][r] = (s[l] == s[r] && dp[l+2][r-2]);
}
root = createnode();
REP(i,n)Insert(i);
dfs(root,k);
foreach(i,ans) putchar(*i);
}
方法二:
//GNU C++ Accepted 374 ms 392200 KB
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
using namespace std;
typedef long long ll; const int N = 5000+5;
int dp[N][N];
char s[N];
int k;
int n;
struct node
{
node *son[2];
int cnt;
node()
{
memset(son,0,sizeof(son));
cnt = 0;
}
}trie[N*N];
int SZ = 0;
node *root,*cur;
node *createnode()
{
return &trie[SZ++];
}
void Insert(int p)
{
cur = root;
for(int i = p;i <= n;i++)
{
int val = s[i]-'a';
if(cur->son[val] == NULL) cur->son[val] = createnode();
cur = cur->son[val];
if(i != p)cur->cnt += dp[p][n]-dp[p][i-1];
else cur->cnt += dp[p][n];
}
} void query(node*cur,int k) //二分过程
{
if(k <= 0) return ;
if(cur->son[0] && cur->son[0]->cnt >= k)
{
int cnt = cur->son[0]->cnt;
cur = cur->son[0];
if(cur->son[0]) cnt -= cur->son[0]->cnt;
if(cur->son[1]) cnt -= cur->son[1]->cnt;
putchar('a');
query(cur,k-cnt);
}
else if(cur->son[1])
{
if(cur->son[0]) k -= cur->son[0]->cnt;
int cnt = cur->son[1]->cnt;
cur = cur->son[1];
if(cur->son[0]) cnt -= cur->son[0]->cnt;
if(cur->son[1]) cnt -= cur->son[1]->cnt;
putchar('b');
query(cur,k-cnt);
}
} int main()
{
scanf("%s%d",s+1,&k);
n = strlen(s+1);
for(int i =0;i <= n+2;i++)
for(int j = i;j >= 0;j--)
dp[i][j] = 1;
for(int len = 2;len <= n;len++)
for(int l = 1;l+len-1 <= n;l++)
{
int r = l+len-1;
dp[l][r] = (s[l] == s[r] && dp[l+2][r-2]);
} REP(i,n)
for(int j = i+1;j <= n;j++) dp[i][j] += dp[i][j-1];
root = createnode();
REP(i,n) Insert(i);
query(root,k);
}
Codeforces Round #311 (Div. 2) E - Ann and Half-Palindrome(字典树+dp)的更多相关文章
- Codeforces Round #311 (Div. 2) E. Ann and Half-Palindrome 字典树/半回文串
E. Ann and Half-Palindrome Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contes ...
- Codeforces Round #343 (Div. 2) D - Babaei and Birthday Cake 线段树+DP
题意:做蛋糕,给出N个半径,和高的圆柱,要求后面的体积比前面大的可以堆在前一个的上面,求最大的体积和. 思路:首先离散化蛋糕体积,以蛋糕数量建树建树,每个节点维护最大值,也就是假如节点i放在最上层情况 ...
- Codeforces Round #338 (Div. 2) B. Longtail Hedgehog 记忆化搜索/树DP
B. Longtail Hedgehog This Christmas Santa gave Masha a magic picture and a pencil. The picture con ...
- Codeforces Round #311 (Div. 2) A,B,C,D,E
A. Ilya and Diplomas 思路:水题了, 随随便便枚举一下,分情况讨论一下就OK了. code: #include <stdio.h> #include <stdli ...
- Codeforces Round #311 (Div. 2) D. Vitaly and Cycle 图论
D. Vitaly and Cycle Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/557/p ...
- Codeforces Round #311 (Div. 2) C. Arthur and Table Multiset
C. Arthur and Table Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/557/p ...
- Codeforces Round #311 (Div. 2)B. Pasha and Tea 水题
B. Pasha and Tea Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/557/prob ...
- Codeforces Round #311 (Div. 2) A. Ilya and Diplomas 水题
A. Ilya and Diplomas Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/557/ ...
- Codeforces Round #311 (Div. 2)题解
A. Ilya and Diplomas time limit per test 1 second memory limit per test 256 megabytes input standard ...
随机推荐
- 详解C++ friend关键字
1. 为什么要使用友元? 通常对于普通函数来说,要访问类的保护成员是不可能的,如果想这么做那么必须把类的成员都生命成为 public( 共用的) ,然而这做带来的问题遍是任何外部函数都可以毫无约束的访 ...
- rpm包安装
RPM全称是“RedHatPackageManager”是由RedHat公司发发展起来的,本质是将软件源码包经过编译并且打包成rpm的格式,rpm文件包含的有二进制文件,配置文件,库文件等,同时RPM ...
- scala学习笔记-集合
变长数组:数组缓冲 Scala中对于那种长度会变的数组的数据结构为ArrayBuffer. import scala.collection.mutable.ArrayBuffer; // 一个空的数组 ...
- 127.0.0.1与localhost与ip的区别
127.0.0.1与localhost与ip的区别 May 18, 2014 localhost 不联网不使用网卡,不受防火墙和网卡限制本机访问 一般使用 本地套接字文件AF_UNIX 应用程序一般约 ...
- DataTable循环删除行
1.如果只是想删除datatable中的一行,可以用DataRow的delete,但是必须要删除后让DataTable知道,所以就要用 到.AcceptChanges()方法,原因是这种删除只是标识性 ...
- CSS应用二
样式中的顺序问题. 如:padding,margin,border,等,都是按照顺时针方向赋值的,及上右下左. Padding:1px 2px 3px 4px;(top:1px;right:2px;b ...
- HTML&CSS基础学习笔记1.26-input重置表单
重置表单 <input>的[type]属性值为"button"的时候表示一个普通的按钮,相当于一个<button>标签. <input>的[ty ...
- iOS学习之自定义UItableViewCell
在项目开发中,大部分情况下我们都需要自定义UITableViewCell, 今天就重点整理一下目前自己已经学过的自定义Cell的一些注意事项; 分步骤来写吧: 1.将自定义的Cell定义为属性; 2. ...
- Java学习笔记--HashMap中使用object做key的问题【转】
在HashMap中,如果需要使用多个属性组合作为key,可以将这几个属性组合成一个对象作为key.但是存在的问题是,要做get时,往往没办法保存当初put操作时的key object的referenc ...
- Bash 使用技巧大补贴
https://linuxtoy.org/archives/the-best-tips-and-tricks-for-bash.html