Codeforces Round #405 Div. 1 Bear and Company(DP)

185 篇文章 0 订阅
116 篇文章 0 订阅

Bear Limak prepares problems for a programming competition. Of course, it would be unprofessional to mention the sponsor name in the statement. Limak takes it seriously and he is going to change some words. To make it still possible to read, he will try to modify each word as little as possible.

Limak has a string s that consists of uppercase English letters. In one move he can swap two adjacent letters of the string. For example, he can transform a string "ABBC" into "BABC" or "ABCB" in one move.

Limak wants to obtain a string without a substring "VK" (i.e. there should be no letter 'V' immediately followed by letter 'K'). It can be easily proved that it's possible for any initial string s.

What is the minimum possible number of moves Limak can do?

Input

The first line of the input contains an integer n (1 ≤ n ≤ 75) — the length of the string.

The second line contains a string s, consisting of uppercase English letters. The length of the string is equal to n.

Output

Print one integer, denoting the minimum possible number of moves Limak can do, in order to obtain a string without a substring "VK".

Examples
input
4
VKVK
output
3
input
5
BVVKV
output
2
input
7
VVKEVKK
output
3
input
20
VKVKVVVKVOVKVQKKKVVK
output
8
input
5
LIMAK
output
0
Note

In the first sample, the initial string is "VKVK". The minimum possible number of moves is 3. One optimal sequence of moves is:

  1. Swap two last letters. The string becomes "VKKV".
  2. Swap first two letters. The string becomes "KVKV".
  3. Swap the second and the third letter. The string becomes "KKVV". Indeed, this string doesn't have a substring "VK".

In the second sample, there are two optimal sequences of moves. One is "BVVKV"  →  "VBVKV"  →  "VVBKV". The other is "BVVKV"  →  "BVKVV"  →  "BKVVV".

In the fifth sample, no swaps are necessary.

分析:我们考虑按每位去构造,设f[i][j][k][which]表示现在已经用了前i个'V'前j个'K'前k个其他字符且以which这个字符结尾的最小移动距离和,很容易发现对于一个确定的结束状态,其相同类型字符之间的前后顺序从头到尾都是不变的,那么我们就可以根据这个状态来枚举下一个字符选什么,注意如果是以v结尾那么下一个字符一定不能选k.状态书n^3,转移时的处理还要O(n),一共是O(n^4).

#include <bits/stdc++.h>
#define MOD 10000007
using namespace std;
int n,f[77][77][77][3],cnt[3],pos[3],M[80];
char s[80];
void up_data(int &u,int v)
{
	if(u > v) u = v;
}
int main()
{
	memset(f,0x3f,sizeof(f));
	cin>>n;
	cin>>s;
	for(int i = 1;i <= n;i++)
	 if(s[i-1] == 'V') M[i] = 1;
	 else 
	  if(s[i-1] == 'K') M[i] = 2;
	   else M[i] = 0;
	for(int i = 1;i <= n;i++)
	 if(M[i] == 1 && f[1][0][0][1] > n*n) f[1][0][0][1] = i-1;
	 else 
	  if(M[i] == 2 && f[0][1][0][2] > n*n) f[0][1][0][2] = i-1;
	   else
	    if(!M[i] && f[0][0][1][0] > n*n) f[0][0][1][0] = i-1;
	for(int i = 0;i <= n;i++)
	 for(int j = 0;j <= n;j++)
	  for(int k = 0;k <= n;k++)
	   if(i + j + k < n)
	   {
	   		int tot = 0;
			memset(pos,0,sizeof(pos)); 
	        cnt[1] = i,cnt[2] = j,cnt[0] = k;
	        for(int d = 1;d <= n;d++)
	         if(cnt[M[d]]) cnt[M[d]]--;
	         else 
	         {
	         	tot++;
	        	if(!pos[M[d]]) pos[M[d]] = tot;
	    	 }
	   		for(int l = 0;l < 3;l++)
	   		{
	   			if(f[i][j][k][l] > n*n) continue;
	   			up_data(f[i][j][k+1][0],f[i][j][k][l] + pos[0] - 1);
				up_data(f[i+1][j][k][1],f[i][j][k][l] + pos[1] - 1);
				if(l != 1) up_data(f[i][j+1][k][2],f[i][j][k][l] + pos[2] - 1);
	   		}
	   }
	memset(cnt,0,sizeof(cnt));
	for(int i = 1;i <= n;i++) cnt[M[i]]++;
	cout<<min(min(f[cnt[1]][cnt[2]][cnt[0]][0],f[cnt[1]][cnt[2]][cnt[0]][1]),f[cnt[1]][cnt[2]][cnt[0]][2])<<endl;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值