2017SN多校D1T2 note:dp

题意:

  给你一个长度为n的字符串s,并且告诉你有m对字母不能相邻,问你最少在s中取出多少个字符能够使这个字符串合法。

题解:

  表示状态:

    dp[i] = max num of letters

    考虑到第i个字符并且留下了该字符,i以及i之前留下的字符形成的字符串合法,留下字符的最多个数。

  找出答案:

    n - (max dp[i]) (0<=i<n)

  如何转移:

    开一个辅助数组pre[c],c为一个小写字母的序号('a'为0),意为当前以c结尾的最长字符串长度。

    pre数组随着i的枚举而被不断更新,所以当前的pre数组中存的都是i以及i之前的答案。

    假设现在考虑到第i个字符,要更新dp[i]的值。

    if(s[i]-'a'和j可以相邻) dp[i] = max(dp[i], pre[j]);

    枚举i,j即可。 (i<=0<n, 0<=j<26)

  边界条件:

    dp[1] = 1,把其他字符都去掉,只留第i个字符,dp最少为1。

    并且刚开始所有的pre[c]为0。

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 100005
 5 #define MAX_A 30
 6 #define INF 10000000
 7 
 8 using namespace std;
 9 
10 int n,m;
11 int ans=0;
12 int dp[MAX_N];
13 int pre[MAX_A];
14 bool near[MAX_A][MAX_A];
15 string s;
16 
17 void read()
18 {
19     memset(near,false,sizeof(near));
20     cin>>n>>s>>m;
21     for(int i=0;i<m;i++)
22     {
23         char a,b;
24         cin>>a>>b;
25         near[a-'a'][b-'a']=true;
26         near[b-'a'][a-'a']=true;
27     }
28 }
29 
30 void solve()
31 {
32     memset(pre,0,sizeof(pre));
33     for(int i=0;i<n;i++)
34     {
35         dp[i]=1;
36         for(int j=0;j<26;j++)
37         {
38             if(!near[s[i]-'a'][j])
39             {
40                 dp[i]=max(dp[i],pre[j]+1);
41             }
42         }
43         pre[s[i]-'a']=max(pre[s[i]-'a'],dp[i]);
44         ans=max(ans,dp[i]);
45     }
46 }
47 
48 void print()
49 {
50     cout<<n-ans<<endl;
51 }
52 
53 int main()
54 {
55     freopen("note.in","r",stdin);
56     freopen("note.out","w",stdout);
57     read();
58     solve();
59     print();
60 }
原文地址:https://www.cnblogs.com/Leohh/p/7401708.html