• 洛谷 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
    ",(f[n][m][k][1]+f[n][m][k][0])%mod);
        return 0;
    }
    

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

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

    now1就相当于i-1,因为11=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
    ",(f[n&1][m][k][1]+f[n&1][m][k][0])%mod);
    	return 0;
    }
    
  • 相关阅读:
    软件过程管理读书笔记02
    交叉验证
    oracle两张表数据匹配,Oracle-left join两表关联只取B表匹配到的第一条记录
    oracle批量新增
    oracle聚合函数XMLAGG用法简介
    form表单导致url连接重定向问题处理
    请求200,返回没内容,360可以看到response内容(待看),nginx返回内容被截取
    jsonp请求返回前面带有个null
    oracle日期转换的一些坑
    Java中将List<String>转化为以,分割的字符串或相反(转载)
  • 原文地址:https://www.cnblogs.com/last-diary/p/10806678.html
Copyright © 2020-2023  润新知