洛古 P2679 子串 题解

Posted last-diary

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛古 P2679 子串 题解相关的知识,希望对你有一定的参考价值。

P2679 子串

题目描述

首先设f[i][j][p]表示在\(A\)串中选\(i\)个字符被划分为\(k\)段匹配\(B\)串中的\(j\)个字符方案数,但是发现还不够,因为当前选还是不选的\(k\)转移取决于上个字符选没有选没。所以我们再设一维状态\(0/1\)表示当前字符选或者不选的方案数。

转移:1.如果a[i]==b[j]

f[i][j][p][0]=f[i-1][j][p][0]+f[i-1][j][p][1];
这一位不拿,不累加j-1的合法状态
f[i][j][p][1]=f[i-1][j-1][p][0]+f[i-1][j-1][p-1][1]+f[i-1][j-1][p][1];
f[i-1][j-1][p][0] 最后一位不匹配,必须重新划分区间,必须从p中转,不累加p-1的合法状态
f[i-1][j-1][p-1][1] 最后一位匹配,但不重新划分区间,必须从p-1中转,累加p-1的合法状态
f[i-1][j-1][p][1]  最后一位匹配,重新划分一个区间,p不变,直接中转

2.如果a[i]!=b[j]

f[i][j][p][0]=f[i-1][j][p][0]+f[i-1][j][p][1];
同上
f[i][j][p][1]=0 因为字符不同无法匹配,所以直接为0

初始化

    for (int i=0;i<=n;i++)
    f[i][0][0][0]=f[i][0][0][1]=1;
    不管i选几个让B串中匹配的数为0的只有一种,就是什么都不选
    f[0][0][0][0]和f[0][0][0][1]也要初始化,因为中转要用到

70分

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const int N=510,M=51,mod=1e9+7;
char a[N],b[M];
int f[N][M][M][2];
int n,m,k;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s%s",a+1,b+1);
    for (int i=0;i<=n;i++)
    f[i][0][0][0]=1;
    for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
    for (int p=1;p<=k;p++)
    if (a[i]==b[j])
    {
        f[i][j][p][0]=((ll)f[i-1][j][p][0]+f[i-1][j][p][1])%mod;
        f[i][j][p][1]=((ll)f[i-1][j-1][p][1]+f[i-1][j-1][p-1][0]+f[i-1][j-1][p-1][1])%mod;
    }
    else
    {
        f[i][j][p][0]=((ll)f[i-1][j][p][0]+f[i-1][j][p][1])%mod;
        f[i][j][p][1]=0;
    }
    printf("%d\n",(f[n][m][k][1]+f[n][m][k][0])%mod);
    return 0;
}

因为数据比较大,直接\(DP\)\(MLE\),但是我们观察发现,每次中转只用到i-1和i,所以我们用滚动数组来代替第一维

初始设now=1,因为1对xor运算无影响

now^1就相当于i-1,因为1^1=0,0^1=1,所以实现了数组的滚动。

最后输出n^1,如果n是单数,肯定滚动到1,偶数滚动到0,所以判断奇偶。

100分

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const int N=1010,M=210,mod=1e9+7;
char a[N],b[M];
int f[2][M][M][2];
int n,m,k;
bool now=1;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s%s",a+1,b+1);
    f[0][0][0][0]=f[1][0][0][0]=1;
    now=1;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        for (int p=1;p<=k;p++)
        if (a[i]==b[j])
        {
            f[now][j][p][0]=((ll)f[now^1][j][p][0]+f[now^1][j][p][1])%mod;
            f[now][j][p][1]=((ll)f[now^1][j-1][p][1]+f[now^1][j-1][p-1][0]+f[now^1][j-1][p-1][1])%mod;
        }
        else
        {
            f[now][j][p][0]=((ll)f[now^1][j][p][0]+f[now^1][j][p][1])%mod;
            f[now][j][p][1]=0;
        }
        now^=1;
    }
    printf("%d\n",(f[n&1][m][k][1]+f[n&1][m][k][0])%mod);
    return 0;
}

以上是关于洛古 P2679 子串 题解的主要内容,如果未能解决你的问题,请参考以下文章

P2679 子串

P2679 子串

P2679 子串

P2679 子串

洛古最简单50题解(31-40)

洛古最简单50题解(31-40)