1. 程式人生 > >洛古 P2679 子串 題解

洛古 P2679 子串 題解

ble 分區 滾動 一個 ostream 字符 xor運算 math https

P2679 子串

題目描述

首先設f[i][j][p]表示在\(A\)串中選\(i\)個字符被劃分為\(k\)段匹配\(B\)串中的\(j\)個字符方案數,但是發現還不夠,因為當前選還是不選的\(k\)轉移取決於上個字符選沒有選沒。所以我們再設一維狀態\(0/1\)表示當前字符選或者不選的方案數。

轉移:1.如果a[i]==b[j]

f[i][j][p][0]=f[i-1][j][p][0]+f[i-1][j][p][1];
這一位不拿,不累加j-1的合法狀態
f[i][j][p][1]=f[i-1][j-1][p][0]+f[i-1][j-1][p-1][1]+f[i-1][j-1][p][1];
f[i-1][j-1][p][0] 最後一位不匹配,必須重新劃分區間,必須從p中轉,不累加p-1的合法狀態
f[i-1][j-1][p-1][1] 最後一位匹配,但不重新劃分區間,必須從p-1中轉,累加p-1的合法狀態
f[i-1][j-1][p][1]  最後一位匹配,重新劃分一個區間,p不變,直接中轉

2.如果a[i]!=b[j]

f[i][j][p][0]=f[i-1][j][p][0]+f[i-1][j][p][1];
同上
f[i][j][p][1]=0 因為字符不同無法匹配,所以直接為0

初始化

    for (int i=0;i<=n;i++)
    f[i][0][0][0]=f[i][0][0][1]=1;
    不管i選幾個讓B串中匹配的數為0的只有一種,就是什麽都不選
    f[0][0][0][0]和f[0][0][0][1]也要初始化,因為中轉要用到

70分

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const int N=510,M=51,mod=1e9+7;
char a[N],b[M];
int f[N][M][M][2];
int n,m,k;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s%s",a+1,b+1);
    for (int i=0;i<=n;i++)
    f[i][0][0][0]=1;
    for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
    for (int p=1;p<=k;p++)
    if (a[i]==b[j])
    {
        f[i][j][p][0]=((ll)f[i-1][j][p][0]+f[i-1][j][p][1])%mod;
        f[i][j][p][1]=((ll)f[i-1][j-1][p][1]+f[i-1][j-1][p-1][0]+f[i-1][j-1][p-1][1])%mod;
    }
    else
    {
        f[i][j][p][0]=((ll)f[i-1][j][p][0]+f[i-1][j][p][1])%mod;
        f[i][j][p][1]=0;
    }
    printf("%d\n",(f[n][m][k][1]+f[n][m][k][0])%mod);
    return 0;
}

因為數據比較大,直接\(DP\)\(MLE\),但是我們觀察發現,每次中轉只用到i-1和i,所以我們用滾動數組來代替第一維

初始設now=1,因為1對xor運算無影響

now^1就相當於i-1,因為1^1=0,0^1=1,所以實現了數組的滾動。

最後輸出n^1,如果n是單數,肯定滾動到1,偶數滾動到0,所以判斷奇偶。

100分

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const int N=1010,M=210,mod=1e9+7;
char a[N],b[M];
int f[2][M][M][2];
int n,m,k;
bool now=1;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s%s",a+1,b+1);
    f[0][0][0][0]=f[1][0][0][0]=1;
    now=1;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        for (int p=1;p<=k;p++)
        if (a[i]==b[j])
        {
            f[now][j][p][0]=((ll)f[now^1][j][p][0]+f[now^1][j][p][1])%mod;
            f[now][j][p][1]=((ll)f[now^1][j-1][p][1]+f[now^1][j-1][p-1][0]+f[now^1][j-1][p-1][1])%mod;
        }
        else
        {
            f[now][j][p][0]=((ll)f[now^1][j][p][0]+f[now^1][j][p][1])%mod;
            f[now][j][p][1]=0;
        }
        now^=1;
    }
    printf("%d\n",(f[n&1][m][k][1]+f[n&1][m][k][0])%mod);
    return 0;
}

洛古 P2679 子串 題解