zoukankan      html  css  js  c++  java
  • P2516 [HAOI2010]最长公共子序列

    传送门

    看到数据范围,显然 $n^2$ 的 $dp$...

    设 $f[i][j]$ 表示 $A$ 串考虑了前 $i$ 位,$B$ 串考虑了前 $j$ 位,最优情况下的方案数

    但是好像没法判断转移来的是否为最优方案?

    所以再设 $g[i][j]$ 表示 $A$ 串考虑了前 $i$ 位,$B$ 串考虑了前 $j$ 位,最优情况下的匹配数

    那么对于 $g$ 有转移,$g[i][j]=max(g[i-1][j],g[i][j-1])$,如果 $A[i]==B[j]$,那么 $g[i][j]=max(g[i][j],g[i-1][j-1]+1)$

    然后考虑 $f$ 的转移

    如果 $g[i-1][j]==g[i][j]$ 则 $f[i][j]+=f[i-1][j]$,如果 $g[i][j-1]==g[i][j]$ 则 $f[i][j]+=f[i][j-1]$,如果 $A[i]==B[j]$ 并且 $g[i][j]==g[i-1][j-1]$ 那么 $f[i][j]+=g[i-1][j-1]$

    发现输出比答案大...

    仔细分析发现如果 $g[i-1][j-1]==g[i][j]$,那么 $f[i-1][j-1]$ 的贡献会分别通过 $f[i][j-1],f[i-1][j]$ 转移到 $f[i][j]$ ,就被算了两次

    所以如果 $g[i-1][j-1]==g[i][j]$ ,$f[i][j]$ 还要再减去 $f[i-1][j-1]$

    最后,一定要滚动数组

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=5007,mo=1e8;
    inline int fk(int x) { return x>=mo ? x-mo : x; }
    int n,m,f[2][N],g[2][N];
    char a[N],b[N];
    int main()
    {
        scanf("%s",a+1); scanf("%s",b+1);
        n=strlen(a+1)-1,m=strlen(b+1)-1;
        for(int i=0;i<=m;i++) f[0][i]=1;
        int cur=0,pre;
        for(int i=1;i<=n;i++)
        {
            pre=cur; cur^=1; f[cur][0]=1;
            for(int j=1;j<=m;j++) g[cur][j]=f[cur][j]=0;
            for(int j=1;j<=m;j++)
            {
                if(a[i]==b[j]) g[cur][j]=g[pre][j-1]+1,f[cur][j]=f[pre][j-1];
    
                if(g[pre][j]>g[cur][j]) g[cur][j]=g[pre][j],f[cur][j]=f[pre][j];
                else if(g[pre][j]==g[cur][j]) f[cur][j]=fk(f[cur][j]+f[pre][j]);
    
                if(g[cur][j-1]>g[cur][j]) g[cur][j]=g[cur][j-1],f[cur][j]=f[cur][j-1];
                else if(g[cur][j-1]==g[cur][j]) f[cur][j]=fk(f[cur][j]+f[cur][j-1]);
    
                if(g[cur][j]==g[pre][j-1]) f[cur][j]=fk(f[cur][j]-f[pre][j-1]+mo);
            }
        }
        printf("%d
    %d
    ",g[cur][m],f[cur][m]);
        return 0;
    }
  • 相关阅读:
    解决Requires: libc.so.6(GLIBC_2.14)(64bit)错误解决方法
    Linux下安装rpm出现error: Failed dependencies
    使用WordPress搭建个人博客
    Log4j不写入日志文件排错记录
    JAVA EE,JAVA SE,JAVA ME,JDK,JRE,JVM之间的区别
    [转]【maven】解决Missing artifact jdk.tools:jdk.tools:jar:1.6
    Eclipse新建项目介绍
    Android开发-API指南-<permission-group>
    Android开发-API指南-<permission>
    Android开发-API指南-<path-permission>
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11475700.html
Copyright © 2011-2022 走看看