BZOJ 1566 管道取珠

一开始最不好想:答案同时可以表示为两个人分别干这个事情,如果a得到的序列=b得到的序列,那么ans++。

于是我们就可以dp[i][j][k]表示共取出了i个,a在第一根管子里取出j个,b取出k个。

这样的复杂度是n^3,不足以通过本题。

打表发现真正需要的状态很少,于是先bfs出所有的状态,然后for一遍状态即可。

(常数比较大。。。。。)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#define maxn 505
#define maxm 5000050
#define mod 1024523
using namespace std;
int n,m,tot=0,dp[maxm];
char s1[maxn],s2[maxn];
struct status
{
    int x,y,z;
    status (int x,int y,int z):x(x),y(y),z(z) {}
    status () {}
    friend bool operator < (const status &x,const status &y)
    {
        if (x.x!=y.x) return x.x<y.x;
        if (x.y!=y.y) return x.y<y.y;
        return x.z<y.z;
    }
}p[maxm];
map <status,int> mp;
queue <status> q;
void bfs()
{
    status ret=status(0,0,0);p[1]=ret;
    mp[ret]=++tot;q.push(ret);
    while (!q.empty())
    {
        status head=q.front();q.pop();
        int x=head.x,y=head.y,z=head.z;
        if (s2[m-x+y]==s2[m-x+z] && y<=n && z<=n && x-y<m && x-z<m)
        {
            status ret=status(x+1,y,z);
            if (!mp[ret]) {mp[ret]=++tot;p[tot]=ret;q.push(ret);}
        }
        if (s1[n-y]==s2[m-x+z] && y<n && z<=n && x-y<=m && x-z<m)
        {
            status ret=status(x+1,y+1,z);
            if (!mp[ret]) {mp[ret]=++tot;p[tot]=ret;q.push(ret);}
        }
        if (s2[m-x+y]==s1[n-z] && y<=n && z<n && x-y<m && x-z<=m)
        {
            status ret=status(x+1,y,z+1);
            if (!mp[ret]) {mp[ret]=++tot;p[tot]=ret;q.push(ret);}
        }
        if (s1[n-y]==s1[n-z] && y<n && z<n && x-y<=m && x-z<=m)
        {
            status ret=status(x+1,y+1,z+1);
            if (!mp[ret]) {mp[ret]=++tot;p[tot]=ret;q.push(ret);}
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s",s1+1);scanf("%s",s2+1);
    bfs();
    dp[1]=1;
    for (int i=2;i<=tot;i++)
    {
        int x=p[i].x,y=p[i].y,z=p[i].z;
        if (s1[n-y+1]==s1[n-z+1] && y && z)
        {
            status ret=status(x-1,y-1,z-1);
            if (mp[ret]) dp[i]=(dp[i]+dp[mp[ret]])%mod;
        }
        if (s1[n-y+1]==s2[m-x+z+1] && y)
        {
            status ret=status(x-1,y-1,z);
            if (mp[ret]) dp[i]=(dp[i]+dp[mp[ret]])%mod;
        }
        if (s2[m-x+y+1]==s1[n-z+1] && z)
        {
            status ret=status(x-1,y,z-1);
            if (mp[ret]) dp[i]=(dp[i]+dp[mp[ret]])%mod;
        }
        if (s2[m-x+y+1]==s2[m-x+z+1])
        {
            status ret=status(x-1,y,z);
            if (mp[ret]) dp[i]=(dp[i]+dp[mp[ret]])%mod;
        }
    }
    printf("%d\n",dp[mp[status(n+m,n,n)]]);
    return 0;
}
时间: 2024-08-08 09:45:42

BZOJ 1566 管道取珠的相关文章

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][

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

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

洛谷P1758 [NOI2009]管道取珠

题目:https://www.luogu.org/problemnew/show/P1758 题目描述 管道取珠是小X很喜欢的一款游戏.在本题中,我们将考虑该游戏的一个简单改版.游戏画面如图1所示: (图1) 游戏初始时,左侧上下两个管道分别有一定数量的小球(有深色球和浅色球两种类型),而右侧输出管道为空.每一次操作,可以从左侧选择一个管道,并将该管道中最右侧的球推入右边输出管道. 例如:我们首先从下管道中移一个球到输出管道中,将得到图2所示的情况. (图2) 假设上管道中有n个球, 下管道中有

【Luogu】P1758 [NOI2009] 管道取珠

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

管道取珠

平方转化为两个人取到相同的方案,这是一个小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】管道取珠

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

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: [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有