• 【专题】Subsequence


    回文子序列

    ----------------------------

    最长回文子序列

    题目略

    ----------------------------

    这是回文子序列的基础,直接DP即可。

    f[ L ][ R ] 表示区间[ L , R ] 的最长回文子序列长度。

    f[ L ][ R ] = 0 ( L > R )

    f[ L ][ R ] = 1 ( L = R )

    f[ L ][ R ] = f[ L+1 ][ R-1 ] + 2   ( S[ L ]==S[ R ] )

    f[ L ][ R ] = max( f[ L+1 ][ R ] , f[ L ][ R-1 ] )

    ----------------------------

    代码略

    ----------------------------

    环形回文子序列

    HDU 4745 Two Rabbits

    ----------------------------

    重点是用next() prev() 代替l+1,r-1

     在普通的回文子序列dp中 若x>y 则 f[ x ][ y ]没有值

    这为环形dp提供了储存空间。

    ----------------------------

    const int maxn=1111;
    int a[maxn];
    int f[maxn][maxn];
    int n;
    int prev(int x){
        return (x-1+n)%n;
    }
    int next(int x){
        return (x+1)%n;
    }
    
    int dp(int l,int r){
        if (l==r) return 1;
        if (next(l)==r) return 1+(a[l]==a[r]);
        if (f[l][r]!=-1) return f[l][r];
        if (a[l]==a[r]) return f[l][r]=dp(next(l),prev(r))+2;
        return f[l][r]=max(dp(next(l),r),dp(l,prev(r)));
    }
    
    int main()
    {
        int ans;
        while (~scanf("%d",&n)){
            if (n==0) break;
            ans=0;
            memset(f,-1,sizeof(f));
            for (int i=0;i<n;i++){
                scanf("%d",&a[i]);
            }
            if (n==1) ans=1;
            else if (n==2) ans=2;
            else{
                for (int i=0;i<n;i++){
                    ans=max(ans,dp(next(i),prev(i))+1);
                    //ans=max(ans,dp(i,prev(i)));
                    ans=max(ans,dp(next(i),i));
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    ----------------------------

    超长回文子序列

    Codeforces 335 B-Palindrome

    ----------------------------

    题目给出的n范围较大(5*10^5),要求输出长度为100的回文子序列,若不存在则输出最长的。

    注意到隐含条件,序列由小写字母构成,当n>=2600时,必然有某个字母的数量超过100(鸽笼原理),输出100个该字母即可。

    注意输出dp方案的思路。

    此题也可以用纯dp优化解决。

    见题解:    http://codeforces.com/blog/entry/8538

    代码:        http://codeforces.com/contest/335/submission/4221965

    ----------------------------

    const int maxs=55555;
    const int maxn=3333;
    char s[maxs];
    int n;
    int cnt[27];
    char mc;
    char ans[maxs];
    int t;
    int f[maxn][maxn];
    int dp(int l,int r){
        if (l>r) return 0;
        if (l==r) return 1;
        //if (l+1==r) return 1+(s[l]==s[r]);
        if (f[l][r]!=-1) return f[l][r];
        if (s[l]==s[r]) return f[l][r]=dp(l+1,r-1)+2;
        return f[l][r]=max(dp(l,r-1),dp(l+1,r));
    }
    void trace(int l,int r){
        if (l>r) return;
        if (l==r) ans[t++]=s[l];
    	else if (s[l]==s[r]){
    		ans[t++]=s[l];
    		trace(l+1,r-1);
    		ans[t++]=s[r];
    	}
    	else{
    		if (f[l+1][r]<f[l][r-1]) trace(l,r-1);
    		else trace(l+1,r);
    	}
    }
    
    int main()
    {
        cin>>(s+1);
        n=strlen(s+1);
        memset(cnt,0,sizeof(cnt));
        if (n>=2600){
            for (int i=1;i<=n;i++){
                cnt[s[i]-'a']++;
            }
            for (int i=0;i<26;i++){
                if (cnt[i]>=100){
                    mc=i+'a';
                    break;
                }
            }
            for (int i=0;i<100;i++){
                ans[i]=mc;
            }
            ans[100]=0;
            cout<<ans<<endl;
        }
        else{
            memset(f,-1,sizeof(f));
            dp(1,n);
            t=0;
            trace(1,n);
            ans[t]=0;
            //cerr<<"nice"<<endl;
            if (t<=100) cout<<ans<<endl;
            else{
                //cout<<"boy next door"<<endl;
                for (int i=0;i<50;i++) cout<<ans[i];
                for (int i=t-50;i<t;i++) cout<<ans[i];
                cout<<endl;
            }
        }
        return 0;
    }

    ----------------------------

    回文子序列的数量

    HDU 4632 Palindrome subsequence

    ----------------------------

    此题要求输出回文子序列的方案数

    当s[i]==s[j]时 区间[i,j]的方案数为回文ij + 区间[i+1,j-1] 的方案数

    加上区间[i+1,j] [i,j-1]的方案数,减去区间[i+1,j-1]的方案数(容斥)

    ----------------------------

    const int maxn=1111;
    int f[maxn][maxn];
    char s[maxn];
    
    int main()
    {
        int T,n;
        int cas=0;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%s",(s+1));
            n=strlen(s+1);
            clr(f,0);
            for (int i=1;i<=n;i++)
            {
                f[i][i]=1;
                if (s[i]==s[i+1]&&i+1<=n) f[i][i+1]=3;
                else if (i+1<=n) f[i][i+1]=2;
            }
            for (int k=2;k<n;k++)
            {
                for (int i=1;i+k<=n;i++)
                {
                    int j=i+k;
                    if (s[i]==s[j]) f[i][j]=f[i+1][j-1]+1;
                    f[i][j]+=f[i+1][j]+f[i][j-1]-f[i+1][j-1];
                    f[i][j]=(f[i][j]%MOD+MOD)%MOD;
                }
            }
            printf("Case %d: %d
    ",++cas,f[1][n]);
        }
        return 0;
    }
    ----------------------------

    ----------------------------

    公共子序列

    ----------------------------

    最长公共子序列

    HDU 1159 Common Subsequence

    ----------------------------

    这应该是最裸的LCS了,直接dp即可

    f[ L ][ R ] 表示第一个串的前L个数与第二个穿的前R个数的最长公共子序列的长度。

    f[ L ][ R ] = f[ L-1 ][ R-1 ] +1   ( S[ L ]==S[ R ] )

    f[ L ][ R ] = max( f[ L-1 ][ R ] , f[ L ][ R-1 ] )

    ----------------------------

    代码略

    ----------------------------

    三个串的最长公共子序列

    USTC 1301 Common sub-sequence

    Topcoder SRM 298 DIV 1 1000. CountingCommonSubsequences

    ----------------------------

    https://apps.topcoder.com/forums/?module=Thread&threadID=510443&start=0&mc=5#537441

    听说这是很sb的写法。

    以下是岛娘的写法。(完全看不懂 待整理)

    ----------------------------

    #define p1 p1[c]
    #define p2 p2[c]
    #define p3 p3[c]
    #define u dp[i1][i2][i3]
    const int N = 51;
    LL dp[N][N][N];
    int p1[26][N], p2[26][N], p3[26][N];
    
    class CountingCommonSubsequences
    {
    public:
        long long countCommonSubsequences(string s1, string s2, string s3){
            int n1 = SZ(s1), n2 = SZ(s2), n3 = SZ(s3);
            RST(dp);
            REP(c, 26){
                p1[n1] = n1, p2[n2] = n2, p3[n3] = n3;
                DWN(i1, n1, 0) p1[i1] = s1[i1] == 'a' + c ? i1 : p1[i1+1];
                DWN(i2, n2, 0) p2[i2] = s2[i2] == 'a' + c ? i2 : p2[i2+1];
                DWN(i3, n3, 0) p3[i3] = s3[i3] == 'a' + c ? i3 : p3[i3+1];
                dp[p1[0]][p2[0]][p3[0]] = 1;
            }
            LL res = 0;
            REP_3(i1, i2, i3, n1, n2, n3) if (u){
                res += u;
                REP(c, 26) dp[p1[i1+1]][p2[i2+1]][p3[i3+1]] += u;
            }
            return res;
        }
    };

    ----------------------------

    公共递增子序列

    ----------------------------

    ----------------------------

    ----------------------------

    ----------------------------

    递增子序列

    ----------------------------

    最长递增子序列

    暂时缺题

    ----------------------------

    ----------------------------

    ----------------------------

    递增子序列数

    HDU 1423 Greatest Common Increasing Subsequence

    ----------------------------

    ----------------------------

    ----------------------------

    最长条件子序列

    ----------------------------

    最长差值子序列

    HDU 3530 Subsequence

    ----------------------------

    给出一个正整数组成的序列,求他的最大值与最小值差不小于m不大于k的最长子序列。

    ----------------------------

    代码待调整

    const int maxn=110000;
    int a[maxn];
    typedef pair<int,int> PII;
    deque<PII>q1,q2;
    int main()
    {
        int n,m,k;
        int ans,now;
        while (~scanf("%d%d%d",&n,&m,&k))
        {
            ans=0;
            now=0;
            q1.clear();
            q2.clear();
            REP(i,n)
            {
                scanf("%d",&a[i]);
                while (!q1.empty()&&q1.back().first<=a[i]) q1.pop_back();
                q1.push_back(mp(a[i],i));
                while (!q2.empty()&&q2.back().first>=a[i]) q2.pop_back();
                q2.push_back(mp(a[i],i));
                while (!q1.empty()&&!q2.empty()&&q1.front().first-q2.front().first>k)
                {
                    if (q1.front().second<q2.front().second)
                    {
                        now=q1.front().second+1;
                        q1.pop_front();
                    }
                    else
                    {
                        now=q2.front().second+1;
                        q2.pop_front();
                    }
                }
                if (!q1.empty()&&!q2.empty()&&q1.front().first-q2.front().first>=m)
                    ans=max(ans,i-now+1);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }


    ----------------------------

    ----------------------------

  • 相关阅读:
    asp.net 重定向的三种方法
    C# 日期格式转【转】
    PL/SQL %TYPE和%ROWTYPE的区别【转】
    oracle 常用函数【转】
    阿里---arthas---代码诊断工具使用
    线上应用CPU占用过高
    Centos 7搭建Gitlab服务器超详细Centos 7搭建Gitlab服务器超详细(搭建成功)
    G1和CMS垃圾回收数据对比
    定位CPU暂用过高问题排查
    OAutho2----实现单点登录
  • 原文地址:https://www.cnblogs.com/cyendra/p/3681577.html
Copyright © 2020-2023  润新知