Hackerrank:Yet Another KMP Problem

This challenge uses the famous KMP algorithm. It isn't really important to understand how KMP works, but you should understand what it calculates.

A KMP algorithm takes a string,  S S, of length  N N as input. Let's assume that the characters in  S S are indexed from  1 1to  N N; for every prefix of  S S, the algorithm calculates the length of its longest valid border in linear complexity. In other words, for every  i i (where  1iN 1≤i≤N) it calculates the largest  l l (where  0li1 0≤l≤i−1) such that for every  p p(where  1pl 1≤p≤l) there is  S[p]=S[il+p] S[p]=S[i−l+p].

Here is an implementation example of KMP:

kmp[1] = 0;
for (i = 2; i <= N; i = i + 1){
    l = kmp[i - 1];
    while (l > 0 && S[i] != S[l + 1]){
        l = kmp[l];
    }
    if (S[i] == S[l + 1]){
        kmp[i] = l + 1;
    }
    else{
        kmp[i] = 0;
    }
}

Given a sequence  x1,x2,,x26 x1,x2,…,x26, construct a string,  S S, that meets the following conditions:

  1. The frequency of letter ' a a' in  S S is exactly  x1 x1, the frequency of letter ' b b' in  S S is exactly  x2 x2, and so on.
  2. Let's assume characters of  S S are numbered from  1 1 to  N N, where  i=1nxi=N ∑i=1nxi=N. We apply the KMP algorithm to  S S and get a table,  kmp kmp, of size  N N. You must ensure that the sum of  kmp[i] kmp[i] for all  i i is minimal.

If there are multiple strings which fulfill the above conditions, print the lexicographically smallest one.

Input Format

A single line containing  26 26 space-separated integers describing sequence  x x.

Constraints

  • The sum of all  xi xi will be a positive integer  106 ≤106.

Output Format

Print a single string denoting  S S.

Sample Input

2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Sample Output

aabb

Explanation

The output string must have two ' a a' and two ' b b'. There are several such strings but we must ensure that sum of  kmp[i] kmp[i] for all  1<=i<=4 1<=i<=4 is minimal. See the figure below:

The minimum sum is  1 1. Among all the strings that satisfy both the condition, "aabb" is the lexicographically smallest.

题意是给出一个字符串各个字符的出现次数,要使得一个,这个字符的kmp数组的和最小,还要字典序最大。

kmp数组的和最小,其实就是前缀不想等,这样就要把出现次数最少的那个字符放到第一个,然后考虑各种情况,如果这个字符字典序在后面,那直接按字典序排好,输出。

如果这个字符本身在字典序第一位,那么考虑让这个字符与其他字符交叉输出使得前缀字符不相等。

代码:

#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;

#define INF 0x3fffffff
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))
#define mp make_pair
#define ff first
#define ss second
#define pb push_back

const int maxn = 1e6 + 5;
const ll mod = 1000000;
const double PI = acos(-1.0);

vector< pair <int, char> > v;

bool cmp(const pair<int, char>&a, const pair<int, char>&b)
{
	return a.ss < b.ss;
}

void solve()
{
	int i, j, k;
	rep(i, 0, 26)
	{
		sa(k);
		if (k == 0)continue;
		v.pb(mp(k, i + 'a'));
	}
	sort(v.begin(), v.end());
	sort(v.begin() + 1, v.end(), cmp);
	if (v.size() == 1)
	{
		rep(i, 0, v[0].ff)
		{
			printf("%c", v[0].ss);
		}
		printf("\n");
		return;
	}
	int le = 0, ri = 1;
	//buf[cur++] = v[le].ss, v[le].ff--;
	printf("%c", v[le].ss);
	v[le].ff--;
	if (v[le].ss > v[ri].ss)
	{
		sort(v.begin(), v.end(), cmp);
		rep(i, 0, v.size())
		{
			rep(j, 0, v[i].ff)
			{
				printf("%c", v[i].ss);
			}
		}
		printf("\n");
	}
	else
	{
		while (ri < v.size())
		{
			if (v[le].ff)
			{
				v[le].ff--;
				printf("%c", v[le].ss);
			}
			if (v[ri].ff)
			{
				v[ri].ff--;
				printf("%c", v[ri].ss);
				if (v[ri].ff == 0)
				{
					ri++;
				}
			}
		}
	}
}

int main()
{
#ifndef ONLINE_JUDGE  
	freopen("i.txt", "r", stdin);
	freopen("o.txt", "w", stdout);
#endif
	solve();
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值