• 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;
    }
  • 相关阅读:
    python 换行符的识别问题,Unix 和Windows 中是不一样的
    MaxCompute小文件问题优化方案
    MaxCompute小文件问题优化方案
    C++ 中的sort()排序函数用法
    C++ 中的sort()排序函数用法
    简单记录几个有用的sql查询
    bzoj1084(SCOI2005)最大子矩阵
    bzoj1025(SCOI2009)游戏——唯一分解的思路与应用
    bzoj1087互不侵犯King(状压)
    bzoj2748(HAOI2018)音量调节
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11475700.html
Copyright © 2020-2023  润新知