zoukankan      html  css  js  c++  java
  • 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语言描述)
    leetcode-mid- 50. Pow(x,n)-NO
    leetcode-mid-math
    leetcode-mid-math-202. Happy Number-NO
    leetcode-mid-dynamic programming- Longest Increasing Subsequence-NO
    leetcode-mid-design-380. Insert Delete GetRandom O(1)
    leetcode-mid-design-297. Serialize and Deserialize Binary Tree¶-NO -??
    leetcode-mid-dynamic programming-322. Coin Change
    leetcode-mid-dynamic programming-62. Unique Paths
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10458429.html
Copyright © 2011-2022 走看看