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

    [BZOJ2423][HAOI2010]最长公共子序列

    试题描述

    字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij = yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。

    输入

    第1行为第1个字符序列,都是大写字母组成,以”.”结束。长度小于5000。

    第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。

    输出

    第1行输出上述两个最长公共子序列的长度。

    第2行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对100,000,000求余即可。

    输入示例

    ABCBDAB.
    BACBBD.

    输出示例

    4
    7

    数据规模及约定

    见“输入

    题解

    第一问是最裸的最长公共子序列dp;第二问须在第一问基础上加一个计数问题,设 f(i, j) 是第一个串到第 i 位,第二个串到第 j 位的最长公共子序列长度,g(i, j) 为 f(i, j) 取最大值时的方案数,那么只要保证上一步转移前也是最优的情况就可以了,注意减去重复的计数。

    记得开滚动数组!

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
        if(Head == Tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            Tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
    
    #define maxn 5010
    #define MOD 100000000
    char A[maxn], B[maxn], cur;
    int f[2][maxn], g[2][maxn];
    
    int main() {
    	scanf("%s%s", A + 1, B + 1);
    	int na = strlen(A + 1), nb = strlen(B + 1);
    	A[na--] = ''; B[nb--] = '';
    	
    	for(int i = 1; i <= nb; i++) g[0][i] = 1; g[0][0] = g[1][0] = 1;
    	for(int i = 1; i <= na; i++) {
    		cur ^= 1;
    		for(int j = 1; j <= nb; j++) {
    			f[cur][j] = max(f[cur^1][j], f[cur][j-1]);
    			if(A[i] == B[j]) f[cur][j] = max(f[cur][j], f[cur^1][j-1] + 1);
    			g[cur][j] = 0;
    			if(f[cur][j] == f[cur^1][j]) g[cur][j] += g[cur^1][j];
    			if(f[cur][j] == f[cur][j-1]) g[cur][j] += g[cur][j-1];
    			if(f[cur][j] == f[cur^1][j] && f[cur][j] == f[cur][j-1] && f[cur^1][j-1] == f[cur][j]) g[cur][j] -= g[cur^1][j-1];
    			if(A[i] == B[j] && f[cur][j] == f[cur^1][j-1] + 1) g[cur][j] += g[cur^1][j-1];
    			if(g[cur][j] > MOD) g[cur][j] %= MOD;
    			if(g[cur][j] < 0) g[cur][j] = (g[cur][j] % MOD) + MOD;
    //			printf("%d %d: %d %d
    ", i, j, f[cur][j], g[cur][j]);
    		}
    	}
    	
    	printf("%d
    %d
    ", f[cur][nb], g[cur][nb]);
    	
    	return 0;
    }
    
  • 相关阅读:
    5.2 spring5源码--spring AOP源码分析三---切面源码分析
    5.2 spring5源码--spring AOP源码分析二--切面的配置方式
    在Dubbo中使用Zookeeper入门案例
    Dubbo直连方式改造
    Dubbo直连方式
    16.3.3 对矢量可执行的其它操作
    16.3.2 可对矢量(vector)执行的操作
    16.3 标准模板库
    16.2.2 有关智能指针的注意事项
    16.2.1 使用智能指针
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5571424.html
Copyright © 2011-2022 走看看