定义有k个不同的字符的字符串为好字符串。现在给出一个字符串,求解对该字符串的每个前缀Si至少是多少个好字符串的连接,若不能由好字符串连接而成则输出-1。
例:k = 2
abac至少是ab和ac这两个好字符串的连接。
字符串长度<=2e5
一个比较直观的dp方程是这样的
f[i]表示Si的答案
f[i] = min(f[j] + 1) (j < i且Sj + 1…i是好字符串)
直接做时间复杂度是O(n2)。
但是可以通过使用数据结构来使时间复杂度降低到O(nlogn)。
先预处理对于每一个i,j的范围是多少使得Sj…i是好字符串,
把j的区间表示为l[i]和r[i]。从后往前可在O(n)时间内预处理出l[i]和r[i]。
接下来把问题转化为了求区间最小值,接着就可以使用线段树维护了。
Accepted | 10012kb | 109ms | GNU G++ 4.9.2 | 2190Bytes |
---|
#include
#include
#include
#include
using namespace std;
const int maxn = 1e5 * 2 + 10;
char buf[maxn];
int cha[26];
int ql[maxn], qr[maxn];
void init(int len, int k)
{
memset(qr, -1, sizeof qr);
int l = len, ct = 0;
for (int i = len ; i > 0 ; i--)
{
while(ct < k && l > 0)
{
if (!cha[buf[l] - 'a'])
ct++;
cha[buf[l] - 'a']++;
--l;
}
if (ct == k)
qr[i] = l + 1;
if (--cha[buf[i] - 'a'] == 0)
--ct;
}
memset(cha, 0, sizeof cha);
memset(ql, -1, sizeof ql);
l = len, ct = 0;
for (int i = len ; i > 0 ; i--)
{
while(ct <= k && l > 0)
{
if (!cha[buf[l] - 'a'])
ct++;
cha[buf[l] - 'a']++;
--l;
}
if (ct == k + 1)
ql[i] = l + 2;
else if (ct == k && l == 0)
ql[i] = l + 1;
if (--cha[buf[i] - 'a'] == 0)
--ct;
}
}
struct tree
{
int num;
int m;
}t[maxn * 4];
void build(int l, int r, int p)
{
t[p].num = maxn;
if (l == r)
return;
t[p].m = (l + r) / 2;
build(l, t[p].m, 2 * p);
build(t[p].m + 1, r, 2 * p + 1);
}
int query(int l, int r, int ll, int rr, int p)
{
if (l == ll && r == rr)
return t[p].num;
if (ll > t[p].m)
return query(t[p].m + 1, r, ll, rr, 2 * p + 1);
else if (rr <= t[p].m)
return query(l, t[p].m, ll, rr, 2 * p);
return min(
query(l, t[p].m, ll, t[p].m, 2 * p),
query(t[p].m + 1, r, t[p].m + 1, rr, 2 * p + 1));
}
void modify(int l, int r, int p, int pp, int num)
{
if (l == r)
{
t[p].num = num;
return;
}
if (pp <= t[p].m)
modify(l, t[p].m, 2 * p , pp, num);
else
modify(t[p].m + 1, r, 2*p + 1, pp, num);
t[p].num = min(t[p].num, num);
}
int main()
{
int k, len;
scanf("%d%s", &k, buf + 1);
len = strlen(buf + 1);
init(len, k);
build(0, len, 1);
for (int i = 1 ; i <= len ; i++)
{
int ans = -1;
if (ql[i] == 1)
modify(0, len, 1, i, ans = 1);
else if (ql[i] != -1)
{
ans = query(0, len, ql[i] - 1, qr[i] - 1, 1);
//printf("%d\n", ans);
if (ans != maxn)
modify(0, len, 1, i, ++ans);
else
ans = -1;
}
printf("%d ", ans);
}
return 0;
}