CodeForces - 1183H Subsequences (hard version) 特殊数位dp

题目链接:CodeForces - 1183H Subsequences (hard version)

题目

Descripion

The only difference between the easy and the hard versions is constraints.

A subsequence is a string that can be derived from another string by deleting some or no symbols without changing the order of the remaining symbols. Characters to be deleted are not required to go successively, there can be any gaps between them. For example, for the string “abaca” the following strings are subsequences: “abaca”, “aba”, “aaa”, “a” and “” (empty string). But the following strings are not subsequences: “aabaca”, “cb” and “bcaa”.

You are given a string s consisting of n lowercase Latin letters.

In one move you can take any subsequence t of the given string and add it to the set S. The set S can’t contain duplicates. This move costs n−|t|, where |t| is the length of the added subsequence (i.e. the price equals to the number of the deleted characters).

Your task is to find out the minimum possible total cost to obtain a set S of size k or report that it is impossible to do so.

Input

The first line of the input contains two integers n and k (1≤n≤100,1≤k≤1012) — the length of the string and the size of the set, correspondingly.

The second line of the input contains a string s consisting of n lowercase Latin letters.

Output

Print one integer — if it is impossible to obtain the set S of size k, print -1. Otherwise, print the minimum possible total cost to do it.

Examples

input

4 5
asdf

output

4

input

5 6
aaaaa

output

15

input

5 7
aaaaa

output

-1

input

10 100
ajihiushda

output

233

题目分析

题意很简单:给你一个字符串,然后从它的所有子串(包含空串)里选 k k k个,使得这 k k k个子串的长度总和尽可能长,重复子串不可以选两次,如 a a c aac aac的非空子串只有{a,c,ac,aa,aac}。
这题其实解法很多,但是数位dp是最快的,而且也没有任何重复情况需要考虑,更不需要更新时向前查找以前的相同字符。具体思路如下:
d p [ i ] [ j ] dp[i][j] dp[i][j]表示以 A S C I I ASCII ASCII码为 ′ a ′ + i − 1 'a'+i-1 a+i1的字符结尾,总长度为 n n n的子串个数。
我们知道,任意两个相同字符,前一个和它前面的字符生成的子串一定能用后一个与它前面的串生成(因为存在包含关系),也就是说,其实对于同一个字符,前一个位置的存在是没有意义的,它对答案除了前后字符都选,否则其实没有贡献。也就是我们的 d p dp dp数组其实只要开 d p [ 27 ] [ n ] dp[27][n] dp[27][n]就够了,其中27是可能出现的26个小写字母,n是最长的长度。
d e x dex dex 1 1 1更新到 n n n,每次都将它与26个可能字符一一计算,状态转移方程: s t a t e [ i ] = ∑ j = 1 26 d p [ j ] [ i − 1 ] ( 2 ≤ i ≤ n ) state[i] = \sum_{j = 1}^{26}dp[j][i-1] (2\leq i \leq n) state[i]=j=126dp[j][i1](2in) s t a t e [ 1 ] = 1 state[1] = 1 state[1]=1这里 s t a t e [ 1 ] state[1] state[1]必须特判,当然,这个特性也可以作为判断这个字符是否在前面出现过( d p [ i ] [ 1 ] = 0 dp[i][1]=0 dp[i][1]=0说明前面没出现过,这个地方就可以直接剪枝掉了)
然后就是这个方法最骚的部分了,把这个state数组覆盖到原来当前字符对应的dp数组中,如此时字符为 b b b,则把state覆盖到 d p [ 2 ] dp[2] dp[2]上,表示前一个字符已经被后一个相同字符覆盖,因为前一个字符能凑出来的子串,后一个字符一定可以。(注意是覆盖不是相加)
最后遍历一遍即可,上代码:

#include 
#include  
using namespace std;
 
#define maxn 105 
#define ll long long 
ll dp[30][maxn];
char s[maxn];
ll cnt[maxn]; 
ll tmp[maxn]; 
 
int main()
{
     
	int n;
	ll k;
	scanf("%d%lld", &n, &k);
	scanf("\n%s", s);
	for(int i = n; i > 0; i--) 
		s[i] = s[i-1];
	memset(dp, 0, sizeof(dp)); 
	memset(cnt, 0, sizeof(cnt)); 
	dp[s[1]-'a'+1][1] = 1; 
	for(int i = 2; i <= n; i++){
     
		memset(tmp, 0, sizeof(tmp)); 
		tmp[1] = 1; 
		for(int j = 1; j <= 26; j++){
     
			if(dp[j][1] == 0) continue; 
			for(int k = 2; k <= i; k++) 
				tmp[k] += dp[j][k-1]; 
		} 
		for(int k = 1; k <= i; k++)
			dp[s[i]-'a'+1][k] = tmp[k]; 
	} 
	for(int i = 1; i <= 26; i++){
     
		for(int j = 1; j <= n; j++)
			cnt[j] += dp[i][j]; 
	} 
	ll res = 0;
	cnt[0] = 1;
	for(int i = n; i >= 0; i--){
     
		if(k == 0) break; 
		if(k > cnt[i]){
     
			res += (ll)(n-i) * cnt[i]; 	
			k -= cnt[i];	
		} 
		else{
     
			res += (ll)(n-i)*k;
			k = 0; 
		} 
	} 
	if(k != 0) printf("-1\n");
	else printf("%lld\n", res); 
} 

你可能感兴趣的:(动态规划)