NOIP 2015ストリング(DP)

悪い習慣:

\(DP [I] [J ] [K] [1/2] \) 使用して、文字列までのi番目の位置を表し\(K \)の前にj番目の位置bに一致する文字列をサブストリングが選択され、電流i電流のみとするので又はプログラムの数が選択されていない\(I-1 \)に関連する、第1の次元をスクロールすることができます。

転写考慮するとき\([i]が== B [J] \) 、\(DP [ヴァル] [J] [K] [0] =(DP [ヴァル^ 1] [J] [K] [0を] + DP [ヴァル^ 1] [J] [K] [1])%のMo \) 私はこのポジションを選択していないので、彼は、サブ文字列から転送されたJおよびKを使用する1つの場所から一致させることができなければなりません。

Iは、この位置から選択される[J-1] =((DP [ヴァル^ 1] [1] \(DP [ヴァル] [J] [K] [K-1] [0] + DP [ヴァル^ 1] [J-1] [K] [1])%のMo + DP [ヴァル^ 1] [J-1] [K-1] [1])%のMo \)、彼があってもよいように、一つの同じサブ成ります文字列は、また新しい部分になることができます。

とき([I]!= \ \ B [J]) 、私はこの場所を選んだ私は最終的に、値0と一致しないことです。あなたは、にし、同じ場合に選択しない場合。

#include<queue>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mo=1e9+7;
int n,m,p;
char a[1007],b[207];
int dp[2][1007][207][2];//dp[i][j][k][1/2]表示到a串的第i位置为止使用了k个子串匹配到b串的前j个且当前i位置选还是没选的方案数,第一位可以滚动 
int main()
{
 scanf("%d%d%d",&n,&m,&p);
 scanf("%s",a+1);
 scanf("%s",b+1);
 dp[0][0][0][0]=1;//初值
 int val=0;
 for(int i=1;i<=n;i++)
 {
   val^=1;//奇数为1,偶数为0 
   dp[val][0][0][0]=1;
   for(int j=1;j<=min(i,m);j++)
   {
     for(int k=1;k<=min(j,p);k++)
     {
       if(a[i]==b[j])
       {
         dp[val][j][k][0]=(dp[val^1][j][k][0]+dp[val^1][j][k][1])%mo;
         dp[val][j][k][1]=((dp[val^1][j-1][k-1][0]+dp[val^1][j-1][k][1])%mo+dp[val^1][j-1][k-1][1])%mo;
       }
       else
       {
         dp[val][j][k][1]=0;//选了一个不匹配的点 
         dp[val][j][k][0]=(dp[val^1][j][k][0]+dp[val^1][j][k][1])%mo;
       }
     }
   }
 }
 printf("%d\n",(dp[n&1][m][p][0]+dp[n&1][m][p][1])%mo);
 return 0;  
}

おすすめ

転載: www.cnblogs.com/lihan123/p/11698689.html
おすすめ