NOIP2015提高组Day2 子串

题目

这里写图片描述
这里写图片描述

分析

我在考场上就想到了dp,但是。。
算了,没有但是,这就是结果,是自己努力不够的后果。
好,回到正题。

方法0

:(考场的sb方法…..)
f[i,j,k]aibjk
转移十分暴力:a串枚举x,b串枚举y,再判断,然后累加。。

方法1:(by Philipsweng)

fk,i,ja[l,r]<=ibjk
Fk,i,j=Fk,i1,j+ix=1,A[x..i]=B[ji+x..j]Fk1,x1,ji+x1
但是这样太慢了,我们进一步想想优化:
我们发现,若每次这样更新,就没有很好的利用到前面可用的状态。
故,我们接着分析一下 fk1,i,jfk,i,j
Fk,i,j=Fk,i1,j+ix=1,A[x..i]=B[ji+x..j]Fk1,x1,ji+x1
Fk,i1,j1=Fk,i2,j1+i1x=1,A[x..i1]=B[ji+x..j1]Fk1,x1,ji+x1
整理可得:
Fk,i,j=Fk,i1,j,(A[i]=B[j])
Fk,i,j=Fk,i1,j+Fk,i1,j1Fk,i2,j1+Fk1,i1,j1,(A[i]=B[j])

方法2

我们仍然设 fk,i,ja[l,r]<=ibjk
但是我们可以充分利用设来推方程
f[k,i,j]=j1x=1f[k1,i1,x]+f[x,i1,j1]
这样就可以得出一个简单易懂的方程,再加上前缀和优化便可以很好的解决问题了。
为什么这个方程是对的呢?
我们先想,若不分成一组,让 aibj 与前面合为一组,便是 f[x,i1,j1]
接着我们想前面的“最后分开后的最后子串[l,r]<=i”已经帮我们省去n的时间去匹配a串,故我们只需再枚举一次x(x<=j-1),便可以很好的解决问题了。

方法3:

(by cty考场70分方法)
他和一开始我一样是设 f[k,i,j]aibjk ,但想到了前缀和优化,不过他还是枚举了x(x<=j-1)为a倒数x和b匹配即 f[k1,1..i1,x]
若是他设得更好就可以100了。

总结

我一般都很少打noip原题的总结,但是这题却太过“优美”了。。
其实我比赛时思维卡住的原因便是设的不够好,没有运用设去推!
从一开始方法0到方法3到方法2到方法1,这是思维的进步!
从开始枚举全部到枚举部分用前缀和再到用设去推再到观察妙用dp方程
这都是思维的突破,没有做不到只有想不到!
在以后做dp题时要多想状态之间的关系,和方程的优化,加油!

方法1:(by Philipsweng)

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int MAXN = 1005,MAXM = 205,Mo = int(1e9) + 7;

char A[MAXN],B[MAXM];
int F[2][MAXN][MAXM],N,M,K;

int main()
{
    freopen("substring.in","r",stdin),freopen("substring.out","w",stdout);
    scanf("%d%d%d", &N, &M, &K);
    scanf("%s", A + 1);
    scanf("%s", B + 1);
    int cur = 0;
    for(int i = 0;i <= N;i ++)
        F[0][i][0] = 1;
    for(int k = 1;k <= K;k ++)
    {
        cur ^= 1;
        for(int i = 0;i <= N;i ++)
            F[cur][i][k - 1] = 0;
        for(int j = k;j <= M;j ++)
            for(int i = j;i <= N;i ++)
            {
                if (A[i] == B[j])
                {
                    F[cur][i][j] = (F[cur][i - 1][j - 1] + F[cur][i - 1][j]) % Mo;
                    F[cur][i][j] = (F[cur][i][j] + F[cur ^ 1][i - 1][j - 1]) % Mo;
                    if (i >= 2) F[cur][i][j] = (F[cur][i][j] - F[cur][i - 2][j - 1] + Mo) % Mo;
                } else
                    F[cur][i][j] = F[cur][i - 1][j];
            }
    }
    printf("%d\n", F[cur][N][M]);
    return 0;
}

方法2:

const mo=1000000007;
var
    n,m,r,i,j,k,l,t,x,y:longint;
    st,sr:ansistring;
    ans:longint;
    p:boolean;
    f,s:array[0..1,0..200,0..1000] of longint;
function max(l,r:longint):longint;
begin
   if l<r then exit(r);exit(l);
end;
function min(l,r:longint):longint;
begin
   if l>r then exit(r);exit(l);
end;
begin
assign(input,'substring.in');reset(input);
assign(output,'substring.out');rewrite(output);
    readln(n,m,r);
    readln(st);
    readln(sr);
    f[0,0,0]:=1;
    for i:=0 to n do s[0,0,i]:=1;
    x:=1;
    for k:=1 to r do begin
    for i:=1 to m do
        for j:=1 to n do begin
            if sr[i]=st[j] then begin
                f[x,i,j]:=(s[1-x,i-1,j-1]+f[x,i-1,j-1]+f[x,i,j])mod mo;
            end;
            s[x,i,j]:=(f[x,i,j]+s[x,i,j-1])mod mo;
        end;
    x:=1-x;
    fillchar(f[x],sizeof(f[x]),0);
    fillchar(s[x],sizeof(s[x]),0);
    end;
    writeln(s[1-x,m,n]);
close(input);close(output);
end.

方法3:

const
    mo=1000000007;
var
    f,sum:array[0..1,0..200,0..1000] of int64;
    n,m,i,j,k,l,p,t,q:longint;
    ans:int64;
    s,st:ansistring;
begin
    assign(input,'substring.in');reset(input);
    assign(output,'substring.out');rewrite(output);
    readln(n,m,k);
    readln(s);
    readln(st);f[0,0,0]:=1;q:=1;
    for i:=0 to n do sum[0,0,i]:=1;
    for t:=1 to k do
    begin
        for i:=1 to m do
            for j:=1 to n do
            begin
                if st[i]=s[j] then
                begin
                    l:=j;
                    while st[i-j+l]=s[l] do
                    begin
                        f[q,i,j]:=(f[q,i,j]+sum[1-q,i-j+l-1,l-1]) mod mo;
                        dec(l);if (i-j+l=0) or (l=0) then break;
                    end;
                end;
                sum[q,i,j]:=(sum[q,i,j-1]+f[q,i,j]) mod mo;
            end;
        q:=1-q;fillchar(f[q],sizeof(f[q]),0);fillchar(sum[q],sizeof(sum[q]),0);
    end;
    for i:=1 to n do ans:=(ans+f[1-q,m,i]) mod mo;
    writeln(ans);
    close(input);close(output);
end.    
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值