洛谷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 }

原文地址:https://www.cnblogs.com/gjc1124646822/p/8452678.html

时间: 2024-10-11 15:51:24

洛谷P1758 [NOI2009]管道取珠的相关文章

【Luogu】P1758 [NOI2009] 管道取珠

终于开始正式写了.... 题目描述 管道取珠是小X很喜欢的一款游戏.在本题中,我们将考虑该游戏的一个简单改版.游戏画面如图1所示: (图1) 游戏初始时,左侧上下两个管道分别有一定数量的小球(有深色球和浅色球两种类型),而右侧输出管道为空.每一次操作,可以从左侧选择一个管道,并将该管道中最右侧的球推入右边输出管道. 例如:我们首先从下管道中移一个球到输出管道中,将得到图2所示的情况. (图2) 假设上管道中有n个球, 下管道中有m个球,则整个游戏过程需要进行n+m次操作,即将所有左侧管道中的球移

bzoj1566[noi2009]管道取珠

bzoj1566[noi2009]管道取珠 题意: 有个装置,左侧有上下两条管道分别有n个和m个不同颜色的两种球,右侧一条空管道.每次可以选左侧的一条管道将最右侧的球推到右侧管道,经过n+m次操作,右侧管道从右到左形成一个输出序列.求不同种类的输出序列的产生方式数的平方之和.n,m≤500 题解: 将题目转化成两个人同时取,取出来的序列相同的可能性有多少种.于是做dp.方程见代码.f[i][j][k][l]表示第一个人取了i个Aj个B第二个人取了k个Al个B. 代码: 1 #include <c

bzoj 1566: [NOI2009]管道取珠

Description   Input 第一行包含两个整数n, m,分别表示上下两个管道中球的数目. 第二行为一个AB字符串,长度为n,表示上管道中从左到右球的类型.其中A表示浅色球,B表示深色球. 第三行为一个AB字符串,长度为m,表示下管道中的情形. Output 仅包含一行,即为 Sigma(Ai^2) i从1到k 除以1024523的余数. Sample Input 2 1 AB B Sample Output 5 HINT 样例即为文中(图3).共有两种不同的输出序列形式,序列BAB有

1566: [NOI2009]管道取珠 - BZOJ

Description Input第一行包含两个整数n, m,分别表示上下两个管道中球的数目. 第二行为一个AB字符串,长度为n,表示上管道中从左到右球的类型.其中A表示浅色球,B表示深色球. 第三行为一个AB字符串,长度为m,表示下管道中的情形.Output仅包含一行,即为 Sigma(Ai^2) i从1到k 除以1024523的余数.Sample Input2 1ABB Sample Output5HINT 样例即为文中(图3).共有两种不同的输出序列形式,序列BAB有1种产生方式,而序列B

BZOJ 1566 管道取珠(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1566 题意: 思路:假设得到同一个序列S 的方案有ai=3,x,y,z,那么ai^2就是(x,x)(x,y)(x,z)(y,x)(y,y)(y,z)(z,x)(z,y)(z,z),因此我 们可以将原来的一套装置看做两套.f[i][j][p][q]表示从第一套装置的上面取i个下面取j个.从第二套装置的上面取p个下面取q个,且两套装置 得到的两个序列相同的方案数,则答案就是f[n][m][

BZOJ1566 【NOI2009】管道取珠

题面 这是一道DP神题,直到我写下这句题解时也没有想明白-- 首先,这道题要我们求所有(不同输出序列的方案数)的平方和,于是我们当然就想到求所有不同输出序列的方案数--(大雾) .这道题一个巧妙的地方就在于对问题的转化.(以下摘自BYVoid大神的题解) 假设同时有两个人X & Y在玩这个游戏,设X从up取了i个珠子(不一定连续),从down取了j个珠子,取出来的珠子组成的序列为Q,操作序列为x,Y从up取了k个珠子,从down取了l个珠子,取出来的珠子组成的序列也为Q,操作序列为y,那么我们就

BZOJ 1566 管道取珠(DP)

求方案数的平方之和.这个看起来很难解决.如果转化为求方案数的有序对的个数.那么就相当于求A和B同时取,最后序列一样的种数. 令dp[i][j][k]表示A在上管道取了i个,下管道取了j个,B在上管道取了k个,下管道取了i+j-k个珠子的序列相同的种数. 那么状态转移方程显然可得. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include

管道取珠

平方转化为两个人取到相同的方案,这是一个小trick 为什么这样是对的? 假设第一个人取方案是$x$,第二个人取方案是$y$,根据乘法原理就是$x*y$,又因为两个人取得方案数相同所以$x==y$,即$x^2$ 所以设f[a][b][c][d]表示第一个人从第一个管道取a,第一个人从管道取b,第二个人从管道取c,第二个人从管道取d 优化一下可以去掉一维 #include<bits/stdc++.h> using namespace std; #define ll long long #defi

bzoj1566【Noi2009】管道取珠

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1566 两个栈不断pop,共C(n+m,n)种,ai表示每个相同序列的方案数,求∑(ai^2) sol  :首先,将相同的序列看做两个人选取后相同的方案数 考虑Dp,dp[i][j][k][l]表示第一个人从上面选i个,下面选j个,第二个人上k个下l个的答案 显然第四维状态可以由前三维决定 不过还是不太好转移,将状态换为dp[i][j][k]表示选了i个点,第一个人从上面选了j个,第二个人从上