I love you

题目描述

此时相望不相闻,愿逐月华流照君。

一纸情书,到底蕴含了多少倍的爱情呢?

I love you, not only for what you are, but for what I am when I am with you.

输入描述:

共一行:一封若干个字符的情书(大小写不敏感)。

情书不会超过684594个字符(大写、小写字母)。

输出描述:

共一行:包含一个整数,即iloveyou在情书中作为子序列出现的次数。

由于答案可能很大,请输出对20010905取模后的值。

示例1
输入

IloveyouNotonlyforwhatyouareButforwhatIamWhenIamwithyouIloveyouNotonlyforwhatYouhavemadeofyourselfButforwhatYouaremakingofme

输出
2864

思路:竟然没看出来这是个动态规划QwQ。

我们定义dp[i][j]是从字符串前i个字符串中匹配,匹配到iloveyou中第j位出现的次数,这里为了方便

表示下标是从1开始的,其实从0从1开始都一样,为了方便理解就从1开始了。

那么显然:

d p [ i ] [ 1 ] = d p [ i − 1 ] [ 1 ] + ( s [ i ] = = i ) dp[i][1] = dp[i - 1][1] + (s[i] == i) dp[i][1]=dp[i1][1]+(s[i]==i)在c/c++中在一个式子中判等会变成0或1

第i位如果和第一个字符i相等的话,那么dp[i][1] 就是从前i-1个字符中匹配第一个字符i出现的次数加

上这次的。

那么剩下的就是:
d p [ i ] [ 2 ] = d p [ i − 1 ] [ 2 ] + ( s [ i ] = = l ) ∗ d p [ i − 1 ] [ 1 ] dp[i][2] = dp[i - 1][2] + (s[i] == l) * dp[i-1][1] dp[i][2]=dp[i1][2]+(s[i]==l)dp[i1][1]
d p [ i ] [ 3 ] = d p [ i − 1 ] [ 3 ] + ( s [ i ] = = o ) ∗ d p [ i − 1 ] [ 2 ] dp[i][3] = dp[i - 1][3] + (s[i] == o) * dp[i-1][2] dp[i][3]=dp[i1][3]+(s[i]==o)dp[i1][2]
d p [ i ] [ 4 ] = d p [ i − 1 ] [ 4 ] + ( s [ i ] = = v ) ∗ d p [ i − 1 ] [ 3 ] dp[i][4] = dp[i - 1][4] + (s[i] == v) * dp[i-1][3] dp[i][4]=dp[i1][4]+(s[i]==v)dp[i1][3]
d p [ i ] [ 5 ] = d p [ i − 1 ] [ 5 ] + ( s [ i ] = = e ) ∗ d p [ i − 1 ] [ 4 ] dp[i][5] = dp[i - 1][5] + (s[i] == e) * dp[i-1][4] dp[i][5]=dp[i1][5]+(s[i]==e)dp[i1][4]
d p [ i ] [ 6 ] = d p [ i − 1 ] [ 6 ] + ( s [ i ] = = y ) ∗ d p [ i − 1 ] [ 5 ] dp[i][6] = dp[i - 1][6] + (s[i] == y) * dp[i-1][5] dp[i][6]=dp[i1][6]+(s[i]==y)dp[i1][5]
d p [ i ] [ 7 ] = d p [ i − 1 ] [ 7 ] + ( s [ i ] = = o ) ∗ d p [ i − 1 ] [ 6 ] dp[i][7] = dp[i - 1][7] + (s[i] == o) * dp[i-1][6] dp[i][7]=dp[i1][7]+(s[i]==o)dp[i1][6]
d p [ i ] [ 8 ] = d p [ i − 1 ] [ 8 ] + ( s [ i ] = = u ) ∗ d p [ i − 1 ] [ 7 ] dp[i][8] = dp[i - 1][8] + (s[i] == u) * dp[i-1][7] dp[i][8]=dp[i1][8]+(s[i]==u)dp[i1][7]

这里我们只挑 d p [ i ] [ 2 ] = d p [ i − 1 ] [ 2 ] + ( s [ i ] = = l ) ∗ d p [ i − 1 ] [ 1 ] dp[i][2] = dp[i - 1][2] + (s[i] == l) * dp[i-1][1] dp[i][2]=dp[i1][2]+(s[i]==l)dp[i1][1](也就是第一个)来说就行了,剩下的以此类推。

对于之前dp[i][1]的时候,我们能够知道大部分,但是为什么我们这里要乘以一个dp[i-1][1]呢?

我们知道如果第i位与第二个字符l相同的话,那么在1到i-1中所有能跟第1个字符i相同的位置上,都能和当前第i个字符l组成一个子序列(题目中说了是子序列,不是子串),所以要乘以一个dp[i-1][1]

之后的几项类推即可

这里用了滚动数组的方式实现,遍历顺序就不讲了(这个应该是背包的基础吧)

奥对了,还有一点,就是初始状态dp[0][0]我们要初始化成什么

根据定义可知,从前0个字符串中去跟第0个字符(实际不存在)匹配的方案数,那么这种状态是有一个

情况的,所以dp[0][0]要初始化成1

代码:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 684594 + 10;
const int MOD = 20010905;
const char str[] = {"ailoveyou"} ;

int dp[10];
char s[N];

int main(void)
{
    scanf("%s",s + 1);
    
    for(int i = 1 ; s[i] ; ++ i)
    {
        if(s[i] >= 'A' && s[i] <= 'Z')
            s[i] = 'a' + s[i] - 'A';
    }
    
    dp[0] = 1;
    
    for(int i = 1 ; s[i] ; ++ i)
    {
        for(int j = 8 ; j ; -- j)
        {
            dp[j] = (dp[j] + (s[i] == str[j]) * dp[j - 1]) % MOD;
        }
    }
    
    cout << dp[8] % MOD << endl;
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值