L3-2 至多删三个字符

L3-2 至多删三个字符

题意:

给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?

题解:

最不擅长dp
我们设dp[i][j]表示前i里面删除j个有多少种方法
第i个删除或者不删除有两种情况
dp[i][j] = dp[i-1][j] + dp[i-1][j-1]
但是会存在重复的情况,我们还需要去重,什么情况会出现重复?
很明显…X…X这种情况,(…代表中间的几个字符,X代表相同字符)会重复,因为如果把省略号部分删去,再删除前X或者X(只保留一个X),答案就会重复。
所以要去重的情况有,出现两个相同的字符,两个相同字符的距离(坐标差的绝对值)不能超过3,

if(s[k]==s[i])
	dp[i][j] - = dp[k-1][j-(i-k)];

代码:

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<set>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
char s[maxn];
ll dp[maxn][4];
 
int main(){
    
    
	scanf("%s",s+1);
	int len=strlen(s+1);
	dp[0][0]=1;  //讲真,这里赋值为1还是挺疑惑的
	for(int i=1;i<=len;i++){
    
    
		for(int j=0;j<=3;j++){
    
    
			if(i<j) break; //前i个都不够删肯定不行呀
			dp[i][j]=dp[i-1][j];  //第i位字符不删 
			if(j>=1) dp[i][j]+=dp[i-1][j-1];  //第i位字符删
			
			for(int k=i-1;k>=1&&i-k<=j;k--){
    
    
				if(s[k]==s[i]){
    
    
					dp[i][j]-=dp[k-1][j-(i-k)];
					break;
				}
			}
		}
	}
	ll res=0;
	for(int i=0;i<=3;i++){
    
    
		res+=dp[len][i];
	}
	printf("%lld\n",res);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35975367/article/details/115344611