JZOJ 3747 【NOI2014模拟7.14】Problem C

Description

一个基因串只由四个字母组成。
给出一个长度为 N ,仅有四个字母组成的字符串S,问长度为 M 的基因串中,与S的最长公共子序列分别为 0 1 N 的串各有几个。

Data Constraint

N 10 , M 1000

Solution

考虑动态规划,设 Fi,j 表示构造的基因串构造到了第 i 位,S N 个前缀与构造的串的最长公共字符串的状态为j,每次转移时枚举第 i +1位的字符为四个基因串的那个,同时求出新的 j ,由 Fi,j 转移到 Fi+1,j ,这样做是正确的。

分析上述做法的时间复杂度,由于最多只有 N 个前缀,且每个前缀的与构造的串的最长公共子序列的长度最多不过N,所以j的状态最多有 1010 ,这样做显然会超时。

可以发现并不是 j 代表的所有状态都是有意义的。
Ri表示 S 以第i为结尾的前缀与当前构造的基因串的最长公共子序列长度,也就是说 j 对应R数组的所有情况。
Gi = max ( Rj ) ( 1 j i ),易证Gi1 Gi Gi1 + 1
Wi= Gi - Gi1 ,则W_i要么等于 0 ,要么等于1
现在使 j 对应W数组的所有状态,则 j 最大为2N,这样做就可以过了。

Code(Pascal)

const mo=1000000007;
var
    wz:array[1..4] of char=('A','C','G','T');
    ch:array[0..100] of char;
    ans:array[0..1000] of qword;
    g,m2,gg:array[0..15] of longint;
    n,m,h,j,k,l,i,o,p:longint;
    f:array[0..2000,0..2048] of qword;
function max(a,b:longint):longint;
begin if a>b then exit(a) else exit(b); end;
begin
    while not(eoln) do begin
        inc(n); read(ch[n]);
    end;
    readln(m); p:=1; for i:=1 to n do p:=p*2; dec(p);
    m2[1]:=1; for i:=2 to n do m2[i]:=m2[i-1]*2;
    f[0,0]:=1;
    for i:=0 to m-1 do
    for j:=0 to p do
    begin
        f[i,j]:=f[i,j] mod mo; if f[i,j]=0 then continue;
        for l:=1 to n do if j and m2[l]>0 then g[l]:=g[l-1]+1 else g[l]:=g[l-1];
        for k:=1 to 4 do
        begin
            for l:=1 to n do
            if ch[l]=wz[k] then gg[l]:=max(gg[l-1],g[l-1]+1)
            else gg[l]:=max(gg[l-1],g[l]);
            h:=0; for l:=1 to n do  h:=h+m2[l]*(gg[l]-gg[l-1]);
            f[i+1,h]:=f[i+1,h]+f[i,j];
        end;
    end;
    for i:=0 to p do
    begin
        h:=0; for l:=1 to n do if i and m2[l]>0 then inc(h);     
        ans[h]:=(ans[h]+f[m,i]) mod mo;
    end;
    for i:=0 to n do writeln(ans[i]);
end.
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值