题意是:给定一个长度为n(<=100000)的字符串,再给定m个不能相邻的字符。求最少删去多少个,能使得这个字符串是合法的。
第一天模拟赛都是水题,1个小时打完前两题,然后两个小时还是没有推出来这道题的dp,以为推出来的正解最
后只得了四十分,悲伤。
这道题转换一下思路可以当作最长上升子序列的思路来想,dp[i]表示在第i位结尾最长子序列,pre[i]表示以字符i
结尾的最长子序列,用vis[i][j]=0表示i与j可以相连接。那么便可以枚举字符串的每一位i,再枚举每一个字母j,如果现
在的s[i]与j能够相接,那么就有dp[i]=max(dp[i],pre[j]+1),注意每枚举一位就要将pre进行更新。
#include<iostream>
#include<string.h>
#include<stdio.h>
#define maxn 100005
using namespace std;
int dp[maxn];
char s[maxn];
int n,m;
int vis[30][30];
int pre[30];
int main()
{
// freopen("note.in","r",stdin);
// freopen("note.out","w",stdout);
memset(dp,0x3f,sizeof(dp));
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
s[i]=(s[i]-'a'+1);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
char x,y;
cin>>x>>y;
vis[x-'a'+1][y-'a'+1]=1;
vis[y-'a'+1][x-'a'+1]=1;
}
int ans=0;
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<=26;j++)
if(vis[s[i]][j]==0)
{
dp[i]=max(dp[i],pre[j]+1);
}
pre[s[i]]=max(pre[s[i]],dp[i]);
ans=max(ans,dp[i]);
}
printf("%d\n",n-ans);
}