【题解】NOI2009管道取珠

  又是艰难想题的一晚,又是做不出来的一题 (;д;) 好想哭啊……

  这题最关键的一点还是提供一种全新的想法。看到平方和这种东西,真的不好dp。然而我一直陷在化式子的泥潭中出不来。平方能够联想到什么?原本的方案的乘积。将两部分相乘,我们能够联想到这是两个人在取珠,求他们取出来的珠子颜色序列相同的方案数之和。(第一个人要得到 (x) 这种颜色方案有(a_{x})种,第二个人也一样。所以一共为 ({a_{x}}^{2}) 种。到这里,应该就很容易了。虽然看了题解之后恍然大悟,然而深深地明白目前的自己与做出此题之间仍然是有着无法逾越的鸿沟的。唯有坚持努力下去,勤加积累才能够等到柳暗花明的一天 (≧∇≦)ノ

  注意滚动数组哦。

#include <bits/stdc++.h>
using namespace std;
#define maxn 505
#define mod 1024523
int n, m, a[maxn], b[maxn];
int pre = 0, now = 1, f[2][maxn][maxn];
char c;

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

void up(int &x, int y) { x = (x + y) % mod; }

int main()
{
    int n = read(), m = read();
    for(int i = 1; i <= n; i ++)
    {
        cin >> c;
        if(c == 'B') a[n - i + 1] = 1;
    }
    for(int i = 1; i <= m; i ++)
    {
        cin >> c;
        if(c == 'B') b[m - i + 1] = 1;
    }
    f[0][0][0] = 1;
    for(int i = 1; i <= n + m; i ++)
    {
        int lim1 = min(i, n), lim2 = min(i, n);
        for(int j = 0; j <= lim1; j ++)
            for(int k = 0; k <= lim2; k ++)
            {
                f[now][j][k] = 0;
                int x = i - j, y = i - k;
                if(x > m || y > m) continue;
                if(a[j] == a[k]) up(f[now][j][k], f[pre][j - 1][k - 1]);
                if(a[j] == b[i - k]) up(f[now][j][k], f[pre][j - 1][k]);
                if(b[i - j] == a[k]) up(f[now][j][k], f[pre][j][k - 1]);
                if(b[i - j] == b[i - k]) up(f[now][j][k], f[pre][j][k]);
            }
        swap(pre, now);
    }
    printf("%d
", f[pre][n][n]);
    return 0;
}
原文地址:https://www.cnblogs.com/twilight-sx/p/9074810.html