[BZOJ 1566][NOI2009]管道取珠(DP)

Description


hahaha

Input


第一行包含兩個整數n, m,分別表示上下兩個管道中球的數目。 第二行爲一個AB字符串,長度爲n,表示上管道中從左到右球的類型。其中A表示淺色球,B表示深色球。 第三行爲一個AB字符串,長度爲m,表示下管道中的情形。

Output


僅包含一行,即爲 ki=1a2i 除以1024523的餘數。

Sample Input


2 1
AB
B

Sample Output


5

HINT


樣例即爲文中(圖3)。共有兩種不同的輸出序列形式,序列BAB有1種產生方式,而序列BBA有2種產生方式,因此答案爲5。
【大致數據規模】
約30%的數據滿足 n, m ≤ 12;
約100%的數據滿足n, m ≤ 500。

Solution


過了個樣例就開心的交了,然後WA(發現又忘取模了= =)

#我有奇怪的DP技巧系列#?
代碼非常非常短但是思路很神
要求各種序列方案數的平方和,這個平方感覺很難處理…
但是可以轉換一下,假裝有兩個人獨立地各自取球,他們取到完全相同的輸出序列,可以用不同的方法,這樣方案數就變成了ai^2
用f[i][j][k][l]表示a在上面取了i個球,下面取了j個球,b在上面取了k個球,下面取了l個球
因爲此時兩人的輸出序列形式相同,可以知道i+j=k+l,於是可以省掉1維,O(n^3)
空間n^3如果用滾動數組可以n^2

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#define Mod 1024523
using namespace std;
int n,m;
int f[505][505][505];
char s1[505],s2[505];
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s%s",s1+1,s2+1);
    f[0][0][0]=1;
    for(int i=0;i<=n;i++)
    for(int j=0;j<=m;j++)
    for(int k=0;k<=n;k++)
    {
        int l=i+j-k;
        if(i&&k&&s1[i]==s1[k])
        {
            f[i][j][k]+=f[i-1][j][k-1];f[i][j][k]%=Mod;
        }
        if(i&&l&&s1[i]==s2[l])
        {
            f[i][j][k]+=f[i-1][j][k];f[i][j][k]%=Mod;
        }
        if(j&&k&&s2[j]==s1[k])
        {
            f[i][j][k]+=f[i][j-1][k-1];f[i][j][k]%=Mod;
        }
        if(j&&l&&s2[j]==s2[l])
        {
            f[i][j][k]+=f[i][j-1][k];f[i][j][k]%=Mod;
        }

    }
    printf("%d\n",f[n][m][n]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章