[codeforces1132F]Clear the String

time limit per test : 3 seconds
memory limit per test : 256 megabytes

You are given a string s s s of length n n n consisting of lowercase Latin letters. You may apply some operations to this string: in one operation you can delete some contiguous substring of this string, if all letters in the substring you delete are equal. For example, after deleting substring b b b b bbbb bbbb from string a b b b b a c c d d abbbbaccdd abbbbaccdd we get the string a a c c d d aaccdd aaccdd.
Calculate the minimum number of operations to delete the whole string s s s.

Input

The first line contains one integer n ( 1 ≤ n ≤ 500 ) n(1≤n≤500) n(1n500) — the length of string s s s.
The second line contains the string s ( ∣ s ∣ = n ) s(|s|=n) s(s=n) consisting of lowercase Latin letters.

Output

Output a single integer — the minimal number of operation to delete string s s s .

题意:
给一个字符串,你每次操作可以删除一段连续的相同字符,例如字符串 a b b b b a c c d d abbbbaccdd abbbbaccdd删去 b b b b bbbb bbbb之后变成 a c c d d accdd accdd,请问至少操作多少次才会将这个字符串删没。

题解:
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示为把 i i i j j j这个区间删到只剩下字母 k k k的最少操作。
f [ i ] [ j ] [ a ] = m i n ( f [ i ] [ j ] [ a ] , f [ i ] [ k ] [ a ] + f [ k + 1 ] [ j ] [ b ] + ( a ! = b ) ) f[i][j][a] = min(f[i][j][a],f[i][k][a]+f[k+1][j][b]+(a!=b)) f[i][j][a]=min(f[i][j][a],f[i][k][a]+f[k+1][j][b]+(a!=b))
这个算法复杂度是 O ( ( n 3 ) ∗ 26 ∗ 26 ) O((n^3)*26*26) O((n3)2626)
但是其实关于字母的状态数比较少,可以用map优化这个算法,将 f [ i ] [ j ] f[i][j] f[i][j]设为map,然后只要枚举存在的状态即可。

#include<bits/stdc++.h>
#define LiangJiaJun main
#define INF n+4
using namespace std;
int n;
map<int,int>f[504][504];
char s[504];
int LiangJiaJun(){
	scanf("%d",&n);
	scanf("%s",s+1);
	for(int l=1;l<=n;l++){
		for(int i=1;i+l-1<=n;i++){
			int j=i+l-1;
			if(l==1)f[i][j][s[i]-'a']=0;
			for(int k=i;k<j;k++){
				for(auto a:f[i][k]){
					for(auto b:f[k+1][j]){
						if(!f[i][j].count(a.first))f[i][j][a.first]=INF;
						f[i][j][a.first]=min(f[i][j][a.first],(a.second)+(b.second)+((a.first)!=(b.first)));
					}
				}
			}
		}
	}
	int mint=INF;
	for(int i=0;i<26;i++){
        if(!f[1][n].count(i))continue;
        mint=min(mint,f[1][n][i]);
	}
	printf("%d\n",mint+1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值