管道取珠题解DP

管道取珠

https://ac.nowcoder.com/acm/problem/17621

直接入手似乎有些困难,不妨将原问题作一点转化:
输出第i种特定序列的方案数a[i]即为二元组(X, Y)(其中X, Y分别代表一种输出第i种序列的方式,且X与Y相互独立)的组数。
设X所对应的方案为(ix, jx)(从上管道取出了ix个,从下管道取出了jx个),Y所对应的方案为(iy, jy)(含义类似于ix, jx)。
于是,可以用状态f[ix][jx][iy][jy]作一下更新:

1) 若上管道的第(ix + 1)个小球和上管道的第(iy + 1)个小球,那么更新状态f[ix + 1][jx][iy + 1][jy];
2) 若上管道的第(ix + 1)个小球和下管道的第(jy + 1)个小球,那么更新状态f[ix + 1][jx][iy][jy + 1];
3) 若下管道的第(jx + 1)个小球和上管道的第(iy + 1)个小球,那么更新状态f[ix][jx + 1][iy + 1][jy];
4) 若下管道的第(jx + 1)个小球和下管道的第(jy + 1)个小球,那么更新状态f[ix][jx + 1][iy][jy + 1]。
实际上我们知道ix + jx = iy + jy,于是可以减少一维的状态,把jy去掉。
思维性太强了啊 这题

#include <bits/stdc++.h>
using namespace std;
const int maxN = 510, MOD = 1024523;
int f[maxN][maxN][maxN], n, m; char up[maxN], dn[maxN];

inline void Add(int &a, int b)
{if ((a += b) >= MOD) a -= MOD; return;}

int main()
{

    scanf("%d%d%s%s", &n, &m, up + 1, dn + 1); f[0][0][0] = 1;
    for (int ix = 0; ix < n + 1; ++ix)
    for (int jx = 0; jx < m + 1; ++jx)
    for (int iy = 0; iy < n + 1; ++iy)
    if (f[ix][jx][iy])
    {
        int &t = f[ix][jx][iy], jy = ix + jx - iy;
        if (up[ix + 1] == up[iy + 1]) Add(f[ix + 1][jx][iy + 1], t);
        if (up[ix + 1] == dn[jy + 1]) Add(f[ix + 1][jx][iy], t);
        if (dn[jx + 1] == up[iy + 1]) Add(f[ix][jx + 1][iy + 1], t);
        if (dn[jx + 1] == dn[jy + 1]) Add(f[ix][jx + 1][iy], t);
    }
    printf("%d\n", f[n][m][n]);
return 0;
}
全部评论

相关推荐

头像
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务