• 题解 P1758 【[NOI2009]管道取珠】


    题目链接

    Solution [NOI2009]管道取珠

    题目大意:有黑球和白球排成两行,每次可以从任意一行排头取一个球放到输出序列尾部。设得到第 (i) 种输出序列的方案数为 (a_i),求 (sum a_i^2)

    dp、计数


    分析:

    根据乘法原理,方案数的平方和,等于两个人独立地进行操作,然后他们得到相同输出序列的方案数。

    那么我们就可以暴力设一个状态 (f[i][j][k][l]),表示两个人在上面下面分别取了多少个,显然这样会炸掉

    但是发现他们输出序列相同的必要条件是 (i + j = k + l),就可以把状态优化为

    (f[len][i][j]),表示总共取 (len) 个,两个人分别在上下取 (i,j) 个得到相同输出序列的方案数

    转移十分容易,需要使用滚动数组滚掉 (len) 降低空间开销

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    constexpr int maxn = 512,mod = 1024523;
    int f[2][maxn][maxn],n,m;
    char str1[maxn],str2[maxn];
    int main(){
        scanf("%d %d
    ",&n,&m);
        scanf("%s",str1 + 1);
        scanf("%s",str2 + 1);
        f[0][0][0] = 1;
        for(int len = 0;len <= n + m;len++){
            int now = len & 1;
            memset(f[now ^ 1],0,sizeof(f[now ^ 1]));
            for(int i = 0;i <= min(len,n);i++)
                for(int j = 0;j <= min(len,n);j++){
                    if(f[now][i][j] >= mod)f[now][i][j] %= mod;
                    if(!f[now][i][j])continue;
                    if(str1[i + 1] == str1[j + 1])f[now ^ 1][i + 1][j + 1] += f[now][i][j];
                    if(str1[i + 1] == str2[len - j + 1])f[now ^ 1][i + 1][j] += f[now][i][j];
                    if(str2[len - i + 1] == str1[j + 1])f[now ^ 1][i][j + 1] += f[now][i][j];
                    if(str2[len - i + 1] == str2[len - j + 1])f[now ^ 1][i][j] += f[now][i][j];
                }
        }
        printf("%d
    ",f[(n + m) & 1][n][n]);
        return 0;
    }
    
  • 相关阅读:
    Servlet 规范 简介
    Redis简介
    some tips
    初识Servlet
    JVM基础知识
    使用typora编辑博客
    航海が始まる日
    比较好的IT教程网
    vue 使用心得---工作中一些关键点
    Vue父组件主动获取子组件的数据和方法
  • 原文地址:https://www.cnblogs.com/colazcy/p/13930108.html
Copyright © 2020-2023  润新知