【链接】h在这里写链接


【题意】


    给你一个字符串;

    让你把它分割成最多k个部分。

        然后求出每个部分的字符串里面子串的字典序最大的那一个子串。

        然后在这k个子串里面,再选一个字典序最最大的那个。

    作为魔法串。

    要求这个魔法串的字典序尽可能地小.

【题解】


    后缀数组题。

    首先,求出这个串的后缀数组。

    然后看到最大最小这些字样,就应该想到是一道二分的题目了;

        二分啥呢??

        字典序!

    先求出这个字符串的所有不同的子串个数。

    个数就为∑(len-sa[i]-height[i]);

    

    把这个值作为二分的右端点.

    字典序为mid的子串.

    ->可以枚举排名,然后获取出本质排名为mid的子串是哪一个

    又题意等价于,最后的子串,大于等于各个部分的字符串里的所有子串的字典序的最大值.

    

    所以我们可以贪心地选取区间,从最后一个字符开始,逆序往前找,用i枚举,看看这个区间i..区间右端点

    这个子串是不是大于二分的子串,如果是的话,那么就要新加一个区间。这样才能避免子串比所有区间的

    字符串的最大字典序子串来得大。

    (比较可以预处理出来lcp比较,要用到ST表

    ->但也有不可能的情况,即这个字符比二分的子串的首字母来得大,那就直接返回false;

    否则的话,最后选取的区间的个数如果小于等于k的话,返回true;

    否则返回false;



    可以保证,最后二分出来的子串,不会出现在选取的区间的交界处(即横跨两个区间);

    因为如果那样的话(子串横跨),就说明这个选取出来的子串它是比所有区间的子串的最大字典序来得大的.

    那么总可以让他的字典序小一点.使得它是某个区间里面的子串。

    即让>变成==



    记录下选取的子串的左端点和右端点就好。



    (关于本质不同的子串:排名为i的后缀,本来应该有len-Sa[i]个子串,但是因为会和排名第i-1的后缀重

    复Height[i]个,所以要减去Heigh[i]个,则不同的子串数目就是上面那个式子了)

【错的次数】


0

【反思】


在这了写反思

【代码】

#include<bits/stdc++.h>
using namespace std;
#define ll long long const int N = 1e5;
const int MAX_CHAR = 255;//每个数字的最大值。
const int MAXL = 18;//log2数组的最大长度
const int INF = 0x3f3f3f3f;//数值绝对值的最大值
char s[N + 10];//如果是数字,就写成int s[N+10]就好,从0开始存
int Sa[N + 10], T1[N + 10], T2[N + 10], C[N + 10];
int Height[N + 10], Rank[N + 10];
int n,k,t_l,t_r,ans_l,ans_r; void build_Sa(int n, int m) {
int i, *x = T1, *y = T2;
for (i = 0; i<m; i++) C[i] = 0;
for (i = 0; i<n; i++) C[x[i] = s[i]]++;
for (i = 1; i<m; i++) C[i] += C[i - 1];
for (i = n - 1; i >= 0; i--) Sa[--C[x[i]]] = i;
for (int k = 1; k <= n; k <<= 1)
{
int p = 0;
for (i = n - k; i<n; i++) y[p++] = i;
for (i = 0; i<n; i++) if (Sa[i] >= k) y[p++] = Sa[i] - k;
for (i = 0; i<m; i++) C[i] = 0;
for (i = 0; i<n; i++) C[x[y[i]]]++;
for (i = 1; i<m; i++) C[i] += C[i - 1];
for (i = n - 1; i >= 0; i--) Sa[--C[x[y[i]]]] = y[i];
swap(x, y);
p = 1; x[Sa[0]] = 0;
for (i = 1; i<n; i++)
x[Sa[i]] = y[Sa[i - 1]] == y[Sa[i]] && y[Sa[i - 1] + k] == y[Sa[i] + k] ? p - 1 : p++;
if (p >= n) break;
m = p;
}
} struct abc{
int pre2[MAXL+5],need[N+10];
int fmax[N+10][MAXL+5],fmin[N+10][MAXL+5]; void init()
{
pre2[0] = 1;
for (int i = 1;i <= MAXL;i++)
{
pre2[i] = pre2[i-1]<<1;
}
need[1] = 0; need[2] = 1;
int temp = 2;
for (int i = 3; i <= n; i++)//need[i]表示长度为i是2的多少次方,可以理解为[log2i]
if (pre2[temp] == i)
need[i] = need[i - 1] + 1, temp++;
else
need[i] = need[i - 1];
} void getst(int *a,int n)
{
memset(fmax,-INF,sizeof fmax);
memset(fmin,INF,sizeof fmin);
for (int i = 1;i <= n;i++)//下标从0开始就改成对应的就好
fmax[i][0] = fmin[i][0] = a[i]; for (int l = 1;pre2[l]<=n;l++)
for (int i = 1;i <= n;i++)
if (i+pre2[l]-1<=n)
fmax[i][l] = max(fmax[i][l-1],fmax[i+pre2[l-1]][l-1]); for (int l = 1;pre2[l]<=n;l++)
for (int i = 1;i <= n;i++)
if (i+pre2[l]-1<=n)
fmin[i][l] = min(fmin[i][l-1],fmin[i+pre2[l-1]][l-1]);
} int getmin(int l,int r)
{
int len = need[r-l+1];
return min(fmin[l][len],fmin[r-pre2[len]+1][len]);
} int getmax(int l,int r)
{
int len = need[r-l+1];
return max(fmax[l][len],fmax[r-pre2[len]+1][len]);
} }ST; void getHeight(int n)
{
int i, j, k = 0;
for (i = 1; i <= n; i++) Rank[Sa[i]] = i;
for (i = 0; i<n; i++) {
if (k) k--;
j = Sa[Rank[i] - 1];
while (s[i + k] == s[j + k]) k++;
Height[Rank[i]] = k;
}
} void kth(ll pos)
{
for (int i = 1;i <= n;i++)
if (pos > n - Sa[i] - Height[i])
{
pos -= n - Sa[i] - Height[i];
}
else
{
t_l = Sa[i];
t_r = Sa[i] + Height[i] + (int)pos - 1;
break;
}
} int calc(int x1, int y1)
{
if (x1 == y1) return INF;
return ST.getmin(min(Rank[x1], Rank[y1])+1,max(Rank[x1],Rank[y1]));//排名的较小值到最大值之间
//的Height的最小值
} bool cmp(int x1, int y1, int x2,int y2)
{
int l1 = y1 - x1 + 1, l2 = y2 - x2 + 1, lcp = calc(x1, x2);
if (lcp >= l1)
return l1 <= l2;
else
if (lcp >= l2) return 0;//l2 <= lcp < l1
else
return s[x1+lcp] <= s[x2+lcp];
} bool ok()
{
int last = n - 1,p = 1;
for (int i = n - 1; i >= 0; i--)
if (s[i] > s[t_l]) return 0;
else
if (cmp(i,last,t_l,t_r) == 0)
{
p++;
last = i;
}
if (p > k) return false;
return true;
} int main() {
//freopen("F:\\rush.txt", "r", stdin);
scanf("%d", &k);
scanf("%s", s);
n = strlen(s);
s[n] = 0;
build_Sa(n + 1, MAX_CHAR);//注意调用n+1
getHeight(n);
ST.init();
ST.getst(Height, n);
ll r = 0;
for (int i = 1; i <= n; i++) r += (n - Sa[i] - Height[i]);
ll l = 1;
while (l <= r)
{
ll mid = (l + r) >> 1;
kth(mid);
if (ok())
{
ans_l = t_l,ans_r = t_r;
r = mid - 1;
}
else
{
l = mid + 1;
}
}
for (int i = ans_l; i <= ans_r; i++)
putchar(s[i]);
puts("");
return 0;
}

【BZOJ 4310】跳蚤的更多相关文章

  1. bzoj 4310: 跳蚤

    Description 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典 ...

  2. ●BZOJ 4310 跳蚤

    ●赘述题目 给出一个字符串,要求分成k个子串,然后求出每个子串的字典序最大的子串(我称它为子子串),要使这k个子子串中的字典序最大的那个串(即魔力串)最小.输出该魔力串. (本题个人感觉很好,比较综合 ...

  3. bzoj 4310 跳蚤——后缀数组+二分答案+贪心

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 答案有单调性? 二分出来一个子串,判断的时候需要满足那些字典序比它大的子串都不出现! ...

  4. bzoj 4310 跳蚤 —— 后缀数组+二分答案+贪心

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 二分答案——在本质不同的子串中二分答案! 如果二分到的子串位置是 st,考虑何时必须分 ...

  5. bzoj 4310 跳蚤 二分答案+后缀数组/后缀树

    题目大意 给定\(k\)和长度\(\le10^5\)的串S 把串分成不超过\(k\)个子串,然后对于每个子串\(s\),他会从\(s\)的所有子串中选择字典序最大的那一个,并在选出来的\(k\)个子串 ...

  6. bzoj 4310: 跳蚤【后缀数组+st表+二分+贪心】

    先求一下SA 本质不同的子串个数是\( \sum n-sa[i]+1-he[i] \),按字典序二分子串,判断的时候贪心,也就是从后往前扫字符串,如果当前子串串字典序大于二分的mid子串就切一下,然后 ...

  7. 后缀数组 hash求LCP BZOJ 4310: 跳蚤

    后缀数组的题博客里没放进去过..所以挖了一题写写 充实下博客 顺便留作板子.. 一个字符串S中 内容不同的子串 有 sigma{n-sa[i]+1-h[i]}   (噢 这里的h[]就是大家熟知的he ...

  8. 跳蚤 BZOJ 4310

    跳蚤 [问题描述] 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最 ...

  9. bzoj 1220 跳蚤

    Written with StackEdit. Description \(Z\)城市居住着很多只跳蚤.在\(Z\)城市周六生活频道有一个娱乐节目.一只跳蚤将被请上一个高空钢丝的正中央.钢丝很长,可以 ...

随机推荐

  1. javafx tabPane

    public class EffectTest extends Application { @Override public void start(Stage primaryStage) { prim ...

  2. java 参数

    -Xmx:size java最大堆内存 -Xms:size 初始化内存 -Xmn:size 年轻带堆大小 -XX:NewSize=size 年轻带的大小 -XX:NewRatio=ratio 年轻带和 ...

  3. 洛谷 P2242 公路维修问题

    P2242 公路维修问题 题目描述 由于长期没有得到维修,A国的高速公路上出现了N个坑.为了尽快填补好这N个坑,A国决定对M处地段采取交通管制.为了求解方便,假设A国的高速公路只有一条,而且是笔直的. ...

  4. Android SDK使用国内镜像站,解决下载速度慢无法更新?

    1. 国内android开源镜像网站 下面是国内几个比較知名的开源网站.我用的是电子科技大学的镜像源,下载速度很快. mirrors.neusoft.edu.cn //东软信息学院 ubuntu.bu ...

  5. 【MongoDB】mongodump and mongorestore of mogodb

    The another tool will be mentioned in this blog, namely mongodump and mongorestore. General speaking ...

  6. 如果笔记本的 WIN7 运行很卡,请尝试运行这些批处理

    如果笔记本的 WIN7 运行很卡,请尝试运行这些批处理 WIN7是不是很卡?关掉下列服务吧 @echo off rem AppXSvc 为部署应用商店应用程序提供基础结构支持 rem BITS 微软的 ...

  7. Broadcast-广播的接收

    至于广播的意思,不再赘述,直接看它的使用 先看代码 package com.example.test1123; import android.annotation.SuppressLint; impo ...

  8. Android学习笔记进阶19之给图片加边框

    //设置颜色 public void setColour(int color){ co = color; } //设置边框宽度 public void setBorderWidth(int width ...

  9. 用jersey写 java restfull web services 输出xml格式数据

    1 logic package com.toic.rest; import com.toic.model.Folder; import java.util.logging.Logger; import ...

  10. CISP/CISA 每日一题 11

    CISA 每日一题(答) 一个合理建造的数据仓库应当支持下列三种基本的查询格式: 1.向上溯源和向下溯源——向上溯源是对数据进行总计:向下溯源是将数据进行细化: 2.交叉溯源——通过通用属性访问数据仓 ...