• 洛谷 2679 [NOIP 2015] 子串


    题目戳这里
    一句话题意

    给你两个字符串A,B从A中取出K个不重合子串(顺序与在A中顺序相同)组成B,问有多少种方案?

    Solution

    话说重打还是出各种错误也是醉了
    先看题目,因为答案与A串,B串和拆分次数都有关,那么我们把这些都定义进DP方程中:
    定义f[i][j][k][0]代表选到A串的前i个字符中选k个子串组成B[1-j],且第i个不选。
    那么f[i][j][k][1]就是代表选到A串的前i个字符中选k个子串组成B[1-j],且第i个选。
    定义好状态就很好做了:
    如果这个不选,那么很明显就等于前一个 选+不选 ,所以:
    f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1];
    那么如果选呢?首先需要注意因为要选,所以需要A[i]==B[j],否则不匹配。先看转移方程:
    f[i][j][k][1]=f[i-1][j-1][k][1]+f[i-1][j-1][k-1][0]+f[i-1][j-1][k-1][1];
    f[i-1][j-1][k][1]说明选i并且接在i-1后面组成一整个子串。
    f[i-1][j-1][k-1][0] 因为i-1不选,所以需要从k-1转移过来。
    f[i-1][j-1][k-1][1] i-1选了,i也可以单独组成子串。
    注意事项:

    1.因为模数是1e9+7,三个1e9+7就会爆int,所以第二个转移方程需要加两个模一下,再加第三个 (WA了40分)
    2.如果直接定义f数组 空间复杂度是 1000200200*2=8e7 超过了128MB,并且我们的转移方程中 i 的状态只与 i-1 有关,所以需要滚掉第一维。

    Coding

    #include<bits/stdc++.h>
    using namespace std;
    const int P = 1e9+7;
    const int N = 205;
    int t,n,m,f[2][N*5][N][2],K;
    char A[N*5],B[N];
    int main()
    {
        cin>>n>>m>>K;
        scanf("%s",A+1);
        scanf("%s",B+1);
        f[0][0][0][0]=1;
        for(int i=1;i<=n;i++)
        {
            t=!t;f[t][0][0][0]=1;
            for(int j=1;j<=min(i,m);j++)
                for(int k=1;k<=min(j,K);k++)
                    {
                        f[t][j][k][0]=(f[!t][j][k][0]+f[!t][j][k][1])%P;
                        if(A[i]==B[j]) 
                        {
                        	f[t][j][k][1]=(f[!t][j-1][k][1]+f[!t][j-1][k-1][0])%P;
                        	f[t][j][k][1]=(f[t][j][k][1]+f[!t][j-1][k-1][1])%P;
                        }
                        else f[t][j][k][1]=0;
                    }
        }
        cout<<(f[t][m][K][1]+f[t][m][K][0])%P;
        return 0;
    }	
    
  • 相关阅读:
    大数据应用期末总评
    分布式文件系统HDFS 练习
    安装Hadoop
    爬虫综合大作业
    爬取全部的校园新闻
    理解爬虫原理
    中文词频统计与词云生成
    复合数据类型,英文词频统计
    字符串操作、文件操作
    了解大数据的特点、来源与数据呈现方式
  • 原文地址:https://www.cnblogs.com/Le-mon/p/9712143.html
Copyright © 2020-2023  润新知