• 洛谷P1758 [NOI2009]管道取珠


    题目:https://www.luogu.org/problemnew/show/P1758

    题目描述

    管道取珠是小X很喜欢的一款游戏。在本题中,我们将考虑该游戏的一个简单改版。游戏画面如图1所示:

    (图1)

    游戏初始时,左侧上下两个管道分别有一定数量的小球(有深色球和浅色球两种类型),而右侧输出管道为空。每一次操作,可以从左侧选择一个管道,并将该管道中最右侧的球推入右边输出管道。

    例如:我们首先从下管道中移一个球到输出管道中,将得到图2所示的情况。

    (图2)

    假设上管道中有n个球, 下管道中有m个球,则整个游戏过程需要进行n+m次操作,即将所有左侧管道中的球移入输出管道。最终n+m个球在输出管道中从右到左形成输出序列。

    爱好数学的小X知道,他共有C(n+m,n)种不同的操作方式,而不同的操作方式可能导致相同的输出序列。举个例子,对于图3所示的游戏情形:

    (图3)

    我们用A表示浅色球,B表示深色球。并设移动上管道右侧球的操作为U,移动下管道右侧球的操作为D,则共有C(2+1,1)=3种不同的操作方式,分别为UUD,UDU,DUU;最终在输出管道中形成的输出序列(从右到左)分别为BAB,BBA,BBA。可以发现后两种操作方式将得到同样的输出序列。

    假设最终可能产生的不同种类的输出序列共有K种,其中:第i种输出序列的产生方式(即不同的操作方式数目)有ai个。聪明的小X早已知道,

    Σai=C(n+m,n)

    因此,小X希望计算得到:

    Σ(ai)^2

    你能帮助他计算这个值么?由于这个值可能很大,因此只需要输出该值对1024523的取模即可(即除以1024523的余数)。

    说明:文中C(n+m,n)表示组合数。组合数C(a,b)等价于在a个不同的物品中选取b个的选取方案数。

    输入输出格式

    输入格式:

     

    输入文件中的第一行为两个整数n,m,分别表示上下两个管道中球的数目。

    第二行中为一个AB字符串,长度为n,表示上管道中从左到右球的类型。其中:A表示浅色球,B表示深色球。

    第三行中为一个AB字符串,长度为m,表示下管道中的情形。

     

    输出格式:

     

    输出文件中仅一行为一个整数,即为 除以1024523的余数。

    输入输出样例

    输入样例#1: 复制
    2 1
    AB
    B
    
    输出样例#1: 复制
    5

    说明

    【样例说明】

    样例即为文中(图3)。共有两种不同的输出序列形式,序列BAB有1种产生方式,而序列BBA有2种产生方式,因此答案为5。

    【数据规模和约定】

    对于30%的数据,满足:m,n<=12;

    对于100%的数据,满足:m,n<=500。

    解析

    果然noi的题就是比较恶心

    我们。。。首先可以按照题目说的做法来一波暴力。

    好了在noi上得了30分开不开心啊~。

    暴力我就不演示了,我们是来研究dp的。。。。。。

    首先,∑(ai^2)该怎么处理。

    这个地方就非常巧妙了。

    假设一种输出方案为A,能输出的方案为ai,

    那么让两个人玩这个游戏,取到相同的A,方案数不就是ai^2吗。。。。。。

    这步思路非常巧妙。

    然后我们可以列出dp方程,

    f[a1][a2][b1][b2]代表取的情况,a代表第一个人,1、2代表上下。

    然后由于a1+a2==b1+b2,我们可以省去一维。

    然后dp转移如下了,转移的条件是颜色相同:

     1 for (a1=0;a1<=n;++a1){
     2         for (a2=0;a2<=m;++a2){
     3             for (b1=0;b1<=n;++b1){
     4                 b2=a1+a2-b1;
     5                 if (b2>m||b2<0) continue;
     6                 if (a[a1+1]==a[b1+1])
     7                     f[a1+1][a2][b1+1]=((f[a1+1][a2][b1+1]+f[a1][a2][b1])%mod+mod)%mod;
     8                 if (a[a1+1]==b[b2+1])  
     9                     f[a1+1][a2][b1]=((f[a1+1][a2][b1]+f[a1][a2][b1])%mod+mod)%mod;
    10                 if (b[a2+1]==a[b1+1])
    11                     f[a1][a2+1][b1+1]=((f[a1][a2+1][b1+1]+f[a1][a2][b1])%mod+mod)%mod;
    12                 if (b[a2+1]==b[b2+1])
    13                     f[a1][a2+1][b1]=((f[a1][a2+1][b1]+f[a1][a2][b1])%mod+mod)%mod;
    14             }
    15         }
    16     }
    dp

    然后我们欣喜地去交了,得了70分。。。。。。

    尽管我们压掉了一维,但是空间还是炸了,这样子只能再来一波玄学滚动了。。。

    好的我们再交一次,结果得了10分。。。。。。

    好了数组别忘了清0。

    好了终于a了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 const int maxn=502;
     8 const int mod=1024523;
     9 int n,m;
    10 char a[maxn],b[maxn],c[maxn];
    11 int f[2][maxn][maxn];
    12 int a1,a2,b1,b2;
    13 int cur=0;
    14 void trans(){
    15     for (int i=1;i<=n;++i){
    16         c[i]=a[n-i+1];
    17     }
    18     for (int i=1;i<=n;++i){
    19         a[i]=c[i];
    20     }
    21     for (int i=1;i<=m;++i){
    22         c[i]=b[m-i+1];
    23     }
    24     for (int i=1;i<=m;++i){
    25         b[i]=c[i];
    26     }
    27 }
    28 int main(){
    29     cin>>n>>m;
    30     cin>>a+1;
    31     cin>>b+1;
    32     trans();
    33     f[0][0][0]=1;
    34     for (a1=0;a1<=n;++a1,cur^=1){
    35         for (a2=0;a2<=m;++a2){
    36             for (b1=0;b1<=n;++b1){
    37                 f[cur^1][a2][b1]=0;
    38             }
    39             for (b1=0;b1<=n;++b1){
    40                 b2=a1+a2-b1;
    41                 if (b2>m||b2<0) continue;
    42                 if (a[a1+1]==a[b1+1])
    43                     f[cur^1][a2][b1+1]=((f[cur^1][a2][b1+1]+f[cur][a2][b1])%mod+mod)%mod;
    44                 if (a[a1+1]==b[b2+1])  
    45                     f[cur^1][a2][b1]=((f[cur^1][a2][b1]+f[cur][a2][b1])%mod+mod)%mod;
    46                 if (b[a2+1]==a[b1+1])
    47                     f[cur][a2+1][b1+1]=((f[cur][a2+1][b1+1]+f[cur][a2][b1])%mod+mod)%mod;
    48                 if (b[a2+1]==b[b2+1])
    49                     f[cur][a2+1][b1]=((f[cur][a2+1][b1]+f[cur][a2][b1])%mod+mod)%mod;
    50             }
    51         }
    52     }
    53     printf("%d",f[cur^1][m][n]);
    54     return 0;
    55 }
    View Code
  • 相关阅读:
    不开心的事
    git push 时 error: RPC failed; HTTP 400 curl 55 Send failure: Connection was reset 问题
    Java多线程相关
    angularJS 级联下拉框
    leetcode260 Single Number III
    -2147483648的绝对值
    git 提交信息模板
    rabbitmq at com.rabbitmq.client.impl.Frame.readFrom(Frame.java:91) ~[amqp-client-5.4.3.jar:5.4.3] 错误
    Unity 切换场景的注意点
    Java位运算
  • 原文地址:https://www.cnblogs.com/gjc1124646822/p/8452678.html
Copyright © 2020-2023  润新知