HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
题意:给定一个环形字符串,让他把它分成k份,使得最大的字典序 最小。
思路:二分答案,首先很明显答案所有可能是 n*n种 排序可以先求出最长公共前缀,这样比较就只需要比较公共前缀的下一位就能比较出两种答案的字典序大小,这里公共前缀我用 (2*n)*(2*n) DP 求出 。(也可用后缀数组)。接下来就是判断了:
这里二分出来的答案就是字典序的上界,(对于没一个位置作为起点,长度越长字典序越大)那么对于当前答案每个位置都可以求出一个能向后跳的最大值(根据如果以这个点做一个串的起点那么字典序要小于我们二分到的答案)。
那么问题就转换成能不能找到一个起点恰好跳k次回到本身。
首先我们假设cur[i] 为i能向右跳最大距离。如果所有cur[i]都大于0,那么我们只要找到最小需要跳的次数 x 如果x<=k 那么我们肯定就能通过调整步长使得恰好k次能到达(如果总点数小于k 当然无解)最小的k,可以通过枚举每个起点然后尽量往后跳看要几次即可。
为什么能够尽量往后跳来当最少需要的次数呢:因为如果该字符串中如果存在一个字符小于二分到的答案首字母(那就说明以这个字母开始的所有字符串字典序均小于二分到的答案),那么我们就能通过一次跳跃就完成(这里因为有枚举起点肯定会枚举到)。 如果所有字母均等于答案的首字母(这里不可能存在大于答案首字母的字符,如果存在这种字符,他必定不能往后跳,就删除了),那么每次往后跳就为最优。
那么当cur[i]==0时 表示他不能跳到别人别人也不能跳到他那么就删除这个点如果一个点跳跃区间有覆盖这个点 这跳跃区间减去1 。最多n次删除效率为(n*n)
#include <iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
#define N 2010
using namespace std;
char str[N];
struct node {
int l, r;
int size;
char charat(int x) {
if (x < size)
return str[l + x];
else
return ;
}
} s[N * N];
int lcp[N][N];
int n, k;
int min(int x, int y) {
return x < y ? x : y;
}
int max(int x, int y) {
return x > y ? x : y;
}
int LCP(node a, node b) {
int tmp = lcp[a.l][b.l];
tmp = min(tmp, a.size);
tmp = min(tmp, b.size);
return tmp;
}
bool cmp(node a, node b) {
int tmp = LCP(a, b);
return a.charat(tmp) < b.charat(tmp);
}
void init() {
scanf("%d%d", &n, &k);
scanf(" %s", str);
for (int i = n; i < n * ; ++i)
str[i] = str[i - n];
for (int i = ; i <= n + n; ++i)
lcp[i][n + n] = lcp[n + n][i] = ;
for (int i = n + n - ; i >= ; --i)
for (int j = n + n - ; j >= ; --j) {
if (str[i] == str[j])
lcp[i][j] = lcp[i + ][j + ] + ;
else
lcp[i][j] = ;
} }
bool check(int mid) {
vector<int> cur;
for (int i = ; i < n; ++i) {
int tmp = lcp[s[mid].l][i];
if (tmp >= s[mid].size) {
cur.push_back(s[mid].size);
continue;
}
if (s[mid].charat(tmp) > str[i + tmp])
{
cur.push_back(n);
}
else
cur.push_back(tmp);
}
while (true) {
int flag = ;
for (int i = ; i < cur.size(); ++i) {
if (cur[i] == ) {
flag = ;
for (int j = ; j < i; ++j)
if (j + cur[j] >= i)
cur[j]--;
for (int j = i + ; j < cur.size(); ++j)
if (j + cur[j] >= i + cur.size())
cur[j]--; cur.erase(i + cur.begin());
break;
}
}
if (flag)
break;
}
if (cur.size() < k)
return false;
int len = cur.size();
for (int i = ; i < cur.size(); ++i) { int cnt = ;
for (int j = i; j < i + len; j += cur[j % len])
cnt++; if (cnt <= k)
return true;
} return false;
}
void solve() {
int tail = ;
for (int i = ; i < n; ++i) {
for (int j = i; j < i + n; ++j) {
s[tail].size = j - i + ;
s[tail].l = i;
s[tail++].r = j;
}
}
sort(s, s + tail, cmp);
int l = , r = tail - ;
while (r - l > ) {
int mid = (l + r) >> ;
if (check(mid))
r = mid;
else
l = mid;
}
int ans;
if (check(l))
ans = l;
else
ans = r;
for (int i = ; i < s[ans].size; ++i)
printf("%c", s[ans].charat(i));
puts("");
}
int main() {
int tt;
scanf("%d", &tt);
while (tt--) {
init();
solve();
}
return ;
}
HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )的更多相关文章
- HDU 4898 The Revenge of the Princess’ Knight(后缀数组+二分+暴力)(2014 Multi-University Training Contest 4)
Problem Description There is an old country and the king fell in love with a devil. The devil always ...
- hdu 4898 The Revenge of the Princess’ Knight
传送阵:http://acm.hdu.edu.cn/showproblem.php?pid=4898 题目大意:一个首尾相连的字符串,将其分为k个子串,使得最大的字串最小 将所有子串排序,输出第k小即 ...
- 【HDU 4898】 The Revenge of the Princess’ Knight (后缀数组+二分+贪心+...)
The Revenge of the Princess’ Knight Problem Description There is an old country and the king fell in ...
- HDU 4897 Little Devil I(树链剖分)(2014 Multi-University Training Contest 4)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4897 Problem Description There is an old country and ...
- HDU 3987 Harry Potter and the Forbidden Forest(边权放大法+最小割)
Harry Potter and the Forbidden Forest Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65536/ ...
- HDU 1028 Ignatius and the Princess III (母函数或者dp,找规律,)
Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...
- 【HDU - 1029】Ignatius and the Princess IV (水题)
Ignatius and the Princess IV 先搬中文 Descriptions: 给你n个数字,你需要找出出现至少(n+1)/2次的数字 现在需要你找出这个数字是多少? Input ...
- HDU 4900 NO ACM NO LIFE(概率+枚举+搜索)(2014 Multi-University Training Contest 4)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4900 Problem Description There is an old country and ...
- hdu1027 Ignatius and the Princess II (全排列 & STL中的神器)
转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=1027 Ignatiu ...
随机推荐
- 执行gem install linne时报错
由于linner安装实际上是从 rubygems.org 获得的,而其被墙,所以,需要寻找国内的镜像进行安装: 第一种方法: gem sources --remove https://rubygems ...
- printk函数日志级别的设置【转】
本文转载自: 下面执行cat /proc/sys/kernel/printk 打印出的四个数字分别代表: 控制台日志级别.默认的消息日志级别.最低的控制台日志级别和默认的控制台日志级别 只有当prin ...
- postgresql如何实现回收站机制
在oracle10G之后:oracle提供一种回收站的机制:即闪回技术.闪回技术通常用于快速简单恢复数据库中出现的认为误操作等逻辑错误.发展到11G之后:回收站更加完善:对在可闪回时间内:数 ...
- Bootstrap_按钮工具栏
单个按钮在Web页面中的运用有时候并不能满足我们的业务需求,常常会看到将多个按钮组合在一起使用,比如富文本编辑器里的一组小图标按钮等. Bootstrap框架为大家提供了按钮组组件. <div ...
- C#的多态性
参考网址:http://www.cnblogs.com/zhangkai2237/archive/2012/12/20/2826734.html 多态的定义:同一操作作用于不同的对象,可以有不同的解释 ...
- BZOJ 3229: [Sdoi2008]石子合并
3229: [Sdoi2008]石子合并 时间限制: 3 Sec 内存限制: 128 MB提交: 497 解决: 240[提交][][] 题目描述 在一个操场上摆放着一排N堆石子.现要将石子有次序 ...
- ARM处理器的寄存器
在ARM体系中通常有以下3种方式控制程序的执行流程: **在正常执行过程中,每执行一条ARM指令,程序计数器(PC)的值加4个字节:每执行一条Thumb指令,程序计数器寄存器(PC)加2个字节.整个过 ...
- iOS核心动画学习整理
最近利用业余时间终于把iOS核心动画高级技巧(https://zsisme.gitbooks.io/ios-/content/chapter1/the-layer-tree.html)看完,对应其中一 ...
- python decorator的理解
一.decorator的作用 装饰器本质上是一个Python函数,可以让其他函数在不做任何代码变动的前提下增加额外功能. 装饰器的返回值也是一个函数对象.python里函数也是对象. 它经常用于有切面 ...
- CodeForces 166B (凸包)
求一个多边形是否完全在另一个凸多边形内. 乍一看,好像要判点在多边形内,但复杂度不允许,仔细一想,可以把两个多边形的点混起来求一个共同的凸包,如果共同的凸包依旧是原来凸包上的点,说明是. #inclu ...