[洛谷P2246] Hello World

题目←

关于次数的dp
发现每个位置的性质除了在此处出现过多少次hello world外,还有其在新的hello world中可能的位置
设g[i][j]为以i为终点,构成helloworld的前j位的方案数
例如在字符串hhelloworld中,g[3][2] = 2;
于是发现
g[i][j] = i1k=1 g[k][j - 1],
使用前缀和维护,用sum[j - 1]更新g[i][j],用g[i][j]更新sum[j];
f[i]表示当前位出现过多少完整的helloworld
发现f[i]仅能由g[i][10]更新,即出现新的以i结尾的构成前10位(全串)的方案数
对答案贡献为g[i][10]

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mod 1000000007
#define LL long long
using namespace std;
const int MAXN = 500000 + 50;
int n;
string s,x;
LL sum[MAXN],f[MAXN],g[MAXN][15];
char c;
int main(){
    while(cin >> x){
        s += x;
    }
    n = s.length();
    for(int i = 0;i < n;i++){
        if(s[i] >= 'A' && s[i] <= 'Z')s[i] += 32;
    }
    for(int i = 0;i < n;i++){
        f[i] = f[i - 1];
        if(s[i] == 'h'){
            g[i][1] = 1;
            sum[1]++;
        }
        else if(s[i] == 'e'){
            g[i][2] = (sum[1]%mod + g[i][2]%mod)%mod;
            sum[2] = (g[i][2]%mod + sum[2]%mod)%mod;
        }
        else if(s[i] == 'l'){
            g[i][3] += sum[2];
            g[i][3] %= mod;
            g[i][4] += sum[3];
            g[i][4] %= mod;
            g[i][9] += sum[8];
            g[i][9] %= mod;
            sum[4] += g[i][4];
            sum[4] %= mod;
            sum[3] += g[i][3];
            sum[3] %= mod;
            sum[9] += g[i][9];
            sum[9] %= mod;
        }
        else if(s[i] == 'o'){
            g[i][5] += sum[4];
            g[i][5] %= mod;
            g[i][7] += sum[6];
            g[i][7] %= mod;
            sum[7] += g[i][7];
            sum[7] %= mod;
            sum[5] += g[i][5];
            sum[5] %= mod;
        }
        else if(s[i] == 'w'){
            g[i][6] += sum[5];
            g[i][6] %= mod;
            sum[6] += g[i][6];
            sum[6] %= mod;
        }
        else if(s[i] == 'r'){
            g[i][8] += sum[7];
            g[i][8] %= mod;
            sum[8] += g[i][8];
            sum[8] %= mod;
        }
        else if(s[i] == 'd'){
            g[i][10] += sum[9];
            g[i][10] %= mod;
            sum[10] += g[i][10];
            sum[10] %= mod; 
            f[i] += g[i][10];//sum[10]包含了所有以前的串,g[i][10]为该位结尾的所有helloworld,故新增g[i][10] 
            f[i] %= mod;
        }
    }
    printf("%lld",f[n - 1]);
    return 0;
}

Tips:
明确各个数组的含义,保证在转移的时候符合实际


11.5
哇我好菜啊
我记录了那么多无用数组
直接把sum和g那个数组合并不就行了吗
还有f不就是一个变量吗
srO

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mod 1000000007
using namespace std;
const int MAXN = 500000 + 50;
int dp[MAXN][15];
char s[] = {'#','h','e','l','l','o','w','o','r','l','d'};
string a,x;
char ss[MAXN];
int len,ans;
int main(){
    while(cin >> x){
        a += x;
    }
    len = a.length();
    for(int i = 0;i < len;i ++){
        if(a[i] >= 'A' && a[i] <= 'Z'){
            a[i] += 32;
        }
        ss[i + 1] = a[i];
    }
    dp[0][0] = 1;
    for(int i = 1;i <= len;i ++){
        for(int j = 0;j <= 10;j ++){
            dp[i][j] = dp[i - 1][j];
            if(ss[i] == s[j] && j){
                dp[i][j] = (dp[i - 1][j - 1]%mod + dp[i][j])%mod;
                if(j == 10)ans = (ans + dp[i - 1][j - 1])%mod;
            }
        }
    }
    cout << ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值