$[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;
}

posted @ 2019-10-27 12:53  DTTTTTTT  阅读(158)  评论(0编辑  收藏  举报