• HAOI2010 最长公共子序列


    题目链接:戳我

    30分暴力。。。。暴力提取子序列即可qwqwq

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<map>
    #define MAXN 5010
    using namespace std;
    int lena,lenb,n,ans,cnt;
    int dp[MAXN][MAXN];
    char a[MAXN],b[MAXN],cur[MAXN],pre[MAXN];
    map<string,int>sum;
    inline void init(int pos)
    {
        if(cnt==n)
        {
            string s;
            for(int i=1;i<=cnt;i++) s+=pre[i];
            sum[s]++;
            return;
        }
        if(pos>=lenb) return;
        for(int i=pos+1;i<=lenb;i++)
        {
            pre[++cnt]=b[i];
            init(i);
            cnt--;
        }
    }
    inline void solve(int pos)
    {
        if(cnt==n)
        {
            string s;
            for(int i=1;i<=cnt;i++) s+=cur[i];
            ans+=sum[s];
            return;
        }
        if(pos>=lena) return;
        for(int i=pos+1;i<=lena;i++)
        {
            cur[++cnt]=a[i];
            solve(i);
            cnt--;
        }
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        freopen("ce.out","w",stdout);
        #endif
        scanf("%s%s",a+1,b+1);
        lena=strlen(a+1)-1;
        lenb=strlen(b+1)-1;
        for(int i=1;i<=lena;i++)
        {
            for(int j=1;j<=lenb;j++)
            {
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                if(a[i]==b[j]) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
            }
        }
        n=dp[lena][lenb];
        init(0);
        cnt=0;
        solve(0);
        printf("%d
    %d
    ",n,ans);
        return 0;
    }
    
    

    考虑满分算法?题解的话强烈安利Flash_hu dalao的题解

    第一问很好做,也就是f[i][j]表示第一个序列到第i位,第二个序列到第j位,最长的公共子序列的长度。f[i][j]可以从f[i-1][j]和f[i][j-1]转移过来,如果a[i]==b[j]的话还可以从f[i-1][j-1]+1转移过来。

    对于第二问,我们设sum[i][j]表示第一个序列到第i位,第二个序列到第j位,最长公共子序列长度为f[i][j]的子序列个数。显然如果f[i-1][j]f[i][j]的话,我们是可以从sum[i-1][j]转移过来的,f[i][j-1]f[i][j]同理。额外的,如果f[i-1][j-1]+1==f[i][j]时,我们还可以累加sum[i-1][j-1]的答案。

    就这样就结束了吗?不对,你会发现W掉了。为什么呢?

    这是因为如果当f[i-1][j-1]==f[i][j]的时候,sum[i-1][j-1]的值对sum[i-1][j]和sum[i][j-1]各贡献了一次。而我们累加到sum[i][j]的时候相当于重算了一次,所以还要记得减去哦qwqwq

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 5010
    #define mod 100000000
    using namespace std;
    int lena,lenb;
    int f[2][MAXN],sum[2][MAXN];
    char a[MAXN],b[MAXN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        freopen("ce.out","w",stdout);
        #endif
        scanf("%s%s",a+1,b+1);
        lena=strlen(a+1)-1,lenb=strlen(b+1)-1;
        for(int i=0;i<=lenb;i++) sum[0][i]=1;
        sum[1][0]=1;
        for(int i=1;i<=lena;i++)
        {
            for(int j=1;j<=lenb;j++)
            {
                sum[1][j]=0;
                f[1][j]=max(f[1][j-1],f[0][j]);
                if(a[i]==b[j]) f[1][j]=max(f[1][j],f[0][j-1]+1);
                if(a[i]==b[j]&&f[0][j-1]+1==f[1][j]) sum[1][j]+=(sum[1][j]+sum[0][j-1])%mod;
                if(f[1][j-1]==f[1][j]) sum[1][j]=(sum[1][j]+sum[1][j-1])%mod;
                if(f[0][j]==f[1][j]) sum[1][j]=(sum[1][j]+sum[0][j])%mod;
                if(a[i]!=b[j]&&f[0][j-1]==f[1][j]) sum[1][j]=(sum[1][j]+mod-sum[0][j-1])%mod;
            }
            swap(f[0],f[1]),swap(sum[0],sum[1]);
        }
        printf("%d
    %d
    ",f[0][lenb],sum[0][lenb]);
        return 0;
    }
    
  • 相关阅读:
    (原创)C++ IOC框架
    【教训】为什么不作备份?!
    【教训】php pcntl_fork无法在web服务器环境下使用
    PHP多进程处理并行处理任务实例
    mysql数据库授权
    PHPUnit学习03使用Mock对象解决测试依赖
    [Inside] How to solve one problem?
    [Inside] What’s the assumptions you are making
    算法面试题解答(六)
    [Inside] System Thinking
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10458429.html
Copyright © 2020-2023  润新知