zoukankan      html  css  js  c++  java
  • dp+哈希

    链接:https://ac.nowcoder.com/acm/contest/9984/E
    来源:牛客网

    学会字符串哈希后,动态规划选手九峰想要出一道解法为字符串哈希题,于是wcy给他口胡了一道题,却把九峰难倒了,你能帮他解决这个问题吗?
    给定长度为n的字符串序列a和字符串k,询问a有多少子序列拼接起来等于k。

    输入描述:

    第一行输入一个正整数n(n≤40)和字符串k(∣k∣≤5∗106)
    第二行输入n个字符串a1,a2,...,an,表示给定序列
    数据保证a中的字符串总长度不超过5∗1e6,输入的所有字符均为小写字母

    输出描述:

    一行输出一个整数,表示答案
    示例1

    输入

    复制
    5 abcba
    ab c abc ba abcba

    输出

    复制
    3

    说明

    拼接后等于abcba的子序列有三种:[1,2,4],[3,4],[5]

    。 表示前i个定序列匹配到字符串k第j位的所有合法方案, 所以分为取和不取两种选择,这就类似于01背包了,但是比01背包多了一个点就是取之前需要判断它是否能拼接成字符串k。

    所以状态转移方程为 :
    利用滚动数组,将状态转移方程进一步转化为 :
    使用之前的值,所以别忘记了是逆序遍历。



    这个就是用每一个字串不断更新f数组


    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ll;
    const int base=131; 
    const int maxn=5e6+100;
    const int mod=1e9+7;
    char k[maxn];
    char s[maxn];
    ll p[maxn];
    ll hk[maxn];
    ll hs[maxn];
    ll dp[maxn];
    ll l[maxn];
    ll get_hash(int l,int r){
        return hk[r]-hk[l-1]*p[r-l+1];
    }
    int main(){
        int n;
        cin>>n;
        scanf("%s",k+1);
        int len=strlen(k+1);
        p[0]=1;
        for(int i=1;i<=len;i++){
            hk[i]=hk[i-1]*base+k[i];
            p[i]=p[i-1]*base;
        }
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            l[i]=strlen(s+1);
            for(int j=1;j<=l[i];j++){
                hs[i]=hs[i]*base+s[j];
            }    
        }
        dp[0]=1;
        for(int i=1;i<=n;i++){
            for(int j=len;j>=l[i];j--){
                if(get_hash(j-l[i]+1,j)==hs[i]) dp[j]+=dp[j-l[i]];
            }
        }
        cout<<dp[len]<<endl;
    }
  • 相关阅读:
    法正(25):劝降
    单例模式
    Redis学习笔记(六)---List
    canvas的使用
    HTML5的新特性
    html学习笔记一
    matlab无法使用
    Hadoop笔记(一)
    PL/SQL笔记(一)
    Oracle数据库(二)
  • 原文地址:https://www.cnblogs.com/lipu123/p/14448411.html
Copyright © 2011-2022 走看看