[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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值