$[NOIp2015]$ 子串 $dp$

\(Sol\)

不知道为啥看起来就很\(dp\)的亚子.我们关心的只有\(A\)串当前用到哪一个,\(B\)串已经匹配到哪个位置,已经匹配的被分成了多少段.所以设\(f_{i,j,k,0/1}\)表示\(A\)串用到第\(i\)个,\(B\)串已经匹配到第\(j\)个,分成了\(k\)段,最后一段是否被断开.

瞎转移一波(这里就不详细讲了,看代码也很容易懂)就获得了\(90pts\)的好成绩.还有\(10pts\)呢?数组开不下吖\(QwQ\).我开始居然没想到滚动数组,还乱搞了一波\(map\),发现\(f_{i,j,k,0/1}\)一定是转移到\(f_{i+1,j',k',0/1}\),所以可以滚动第一维,要注意在循环开始的时候清空一维数组.

\(Code\)

#include<bits/stdc++.h>
#define il inline
#define Ri register int
#define go(i,a,b) for(Ri i=a;i<=b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
il int read()
{
    Ri x=0,y=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    return x*y;
}
const int N=1005,mod=1000000007;
int n,m,kk,as,f[2][205][205][2];char s1[N],s2[N];
il void inc(Ri &x,Ri y){x+=y;if(x>=mod)x-=mod;}
int main()
{
    n=read(),m=read(),kk=read();
    scanf("%s",s1+1);scanf("%s",s2+1);
    f[0][0][0][0]=1;
    go(ii,0,n)
    {
        Ri i=ii&1;
        mem(f[i^1],0);
        go(j,0,min(m,ii))
        go(k,0,kk)
        go(g,0,1)
            {
            if(!f[i][j][k][g])continue;
            inc(f[i^1][j][k][0],f[i][j][k][g]);
            if(s1[ii+1]==s2[j+1])
            {
            inc(f[i^1][j+1][k+1][1],f[i][j][k][g]);
            if(g)inc(f[i^1][j+1][k][1],f[i][j][k][g]);
            }
        }
        inc(as,f[i][m][kk][1]);
    }
    printf("%d\n",as);
    return 0;
}
上一篇:[Violet]蒲公英


下一篇:SVN 通过Shell Bash 获取项目Reversion号码