题面

这是一道DP神题,直到我写下这句题解时也没有想明白……

首先,这道题要我们求所有(不同输出序列的方案数)的平方和,于是我们当然就想到求所有不同输出序列的方案数……(大雾) 。这道题一个巧妙的地方就在于对问题的转化。(以下摘自BYVoid大神的题解

假设同时有两个人X & Y在玩这个游戏,设X从up取了i个珠子(不一定连续),从down取了j个珠子,取出来的珠子组成的序列为Q,操作序列为x,Y从up取了k个珠子,从down取了l个珠子,取出来的珠子组成的序列也为Q,操作序列为y,那么我们就得到了一个有序对(x,y),f[i][j][k][l]即表示有序对(x,y)的数量。两个有序对不相同当且仅当x和y不同时相同。

下面证明f[i][j][k][l]即为所求。

已知:取出珠子的序列为Q,x和y分别为一种取珠方法(可相同), 取出Q的方案数为a;

求证:有序对(x,y)的数量等于a2

因为取出Q的方案数为a,所以x & y都有a种取值,且x & y彼此独立,故对于x的每一个取值,y都有a种取值,故有序对(x,y)的数量为a2,命题得证。

博主是个超级大傻*,连空间优化到n2都不会,请各路大神指教。

 #include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <complex>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define rg register
#define ll long long
using namespace std; inline int gi()
{
rg int r = ; rg bool b = ; rg char c = getchar();
while (c < '' || c > '') { if (c == '-') b = ; c = getchar(); }
while (c >= '' && c <= '') { r = r * + c - '', c = getchar(); }
if (b) return r; return -r;
} const int inf = , N = , MOD = ;
int n,m,f[N][N][N];
char S[N],X[N]; inline void input()
{
freopen ("!.in", "r", stdin);
n=gi(), m=gi();
scanf("%s%s",S+,X+);
} inline void output()
{
freopen ("!.out", "w", stdout);
printf("%d\n",f[n][m][n]);
} inline void cal(int &t,int d) { t+=d; if (t >= MOD) t-=MOD; } inline void solve()
{
int i,j,k,l,tmp;
f[][][]=;
for (i=; i<=n; i++)
for (j=; j<=m; j++)
for (k=; k<=n; k++)
{
tmp=f[i][j][k], l=i+j-k;
if (!tmp || !l || l > m) continue;
if (S[i+] == S[k+])
cal(f[i+][j][k+],tmp);
if (X[j+] == S[k+])
cal(f[i][j+][k+],tmp);
if (S[i+] == X[l+])
cal(f[i+][j][k],tmp);
if (X[j+] == X[l+])
cal(f[i][j+][k],tmp);
}
} int main()
{
input();
solve();
output();
return ;
}

Update

博主终于会把空间优化到n^2辣!!!

PS:记得要清零!!!

 #include <bits/stdc++.h>
#define rg register
#define ll long long
using namespace std; inline int gi()
{
rg int r = ; rg bool b = ; rg char c = getchar();
while (c < '' || c > '') { if (c == '-') b = ; c = getchar(); }
while (c >= '' && c <= '') { r = r * + c - '', c = getchar(); }
if (b) return r; return -r;
} const int inf = , N = , MOD = ;
int n,m,f[][N][N];
char S[N],X[N]; inline void input()
{
n=gi(), m=gi();
scanf("%s%s",S,X);
} inline void cal(rg int &t,rg int d)
{
t+=d;
if (t >= MOD)
t-=MOD;
} inline void solve()
{
rg int i,j,k,p,q,l,r,now,lst;
f[][][]=, now=;
for (k=; k<n+m; ++k) //枚举一共选了多少个,因为每次更新都会多选一个,所以只需枚举到 n+m-1
{
l=max(k-m,), r=min(k,n); //计算 S 管道取珠的数量范围
lst=now, now^=;
for (i=l; i<=r; ++i) //分别枚举序列 x,y
for (j=l; j<=r; ++j)
{
p=k-i, q=k-j; //i,j 表示 S 管道取的数量,p,q表示 X 管道的数量
if (!f[lst][i][j])
continue;
if (S[i] == S[j])
cal(f[now][i+][j+],f[lst][i][j]);
if (S[i] == X[q])
cal(f[now][i+][j],f[lst][i][j]);
if (X[p] == S[j])
cal(f[now][i][j+],f[lst][i][j]);
if (X[p] == X[q])
cal(f[now][i][j],f[lst][i][j]);
f[lst][i][j]=; //每次更新后要记得清零
}
}
printf("%d\n",f[now][n][n]);
} int main()
{
input();
solve();
return ;
}

BZOJ1566 【NOI2009】管道取珠的更多相关文章

  1. BZOJ1566 [NOI2009]管道取珠 【dp】

    题目 输入格式 第一行包含两个整数n, m,分别表示上下两个管道中球的数目. 第二行为一个AB字符串,长度为n,表示上管道中从左到右球的类型.其中A表示浅色球,B表示深色球. 第三行为一个AB字符串, ...

  2. bzoj1566: [NOI2009]管道取珠 DP

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=1566 思路 n个球,第i个球颜色为ai,对于颜色j,对答案的贡献为颜色为j的球的个数的平 ...

  3. bzoj1566 [NOI2009]管道取珠——DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1566 一眼看上去很懵... 但是答案可以转化成有两个人在同时取珠子,他们取出来一样的方案数: ...

  4. [bzoj1566][NOI2009]管道取珠

    来自FallDream的博客,未经允许,请勿转载,谢谢. n<=500 神题...... 发现这个平方可以看作两个序列相同的对数  然后就可以表示状态了. f[i][j][k]表示两个序列各选了 ...

  5. 【BZOJ 1566】 1566: [NOI2009]管道取珠 (DP)

    1566: [NOI2009]管道取珠 Time Limit: 20 Sec  Memory Limit: 650 MBSubmit: 1659  Solved: 971 Description In ...

  6. Bzoj 1566: [NOI2009]管道取珠(DP)

    1566: [NOI2009]管道取珠 Time Limit: 20 Sec Memory Limit: 650 MB Submit: 1558 Solved: 890 [Submit][Status ...

  7. NOI2009 管道取珠 神仙DP

    原题链接 原题让求的是\(\sum\limits a_i^2\),这个东西直接求非常难求.我们考虑转化一下问题. 首先把\(a_i^2\)拆成\((1+1+...+1)(1+1+...+1)\),两个 ...

  8. BZOJ.1566.[NOI2009]管道取珠(DP 思路)

    BZOJ 洛谷 考虑\(a_i^2\)有什么意义:两个人分别操作原序列,使得得到的输出序列都为\(i\)的方案数.\(\sum a_i^2\)就是两人得到的输出序列相同的方案数. \(f[i][j][ ...

  9. 【题解】NOI2009管道取珠

    又是艰难想题的一晚,又是做不出来的一题 (:д:) 好想哭啊…… 这题最关键的一点还是提供一种全新的想法.看到平方和这种东西,真的不好dp.然而我一直陷在化式子的泥潭中出不来.平方能够联想到什么?原本 ...

  10. BZOJ1566:[NOI2009]管道取珠——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1566 https://www.luogu.org/problemnew/show/P1758 题目 ...

随机推荐

  1. 一个能让你了解所有函数调用顺序的Android库

    http://mobile.51cto.com/android-536059.htm 原理 本库其实并没有什么黑科技,本库也没有java代码,核心就是2个build.gradle中的task.首先,原 ...

  2. javascript 对象初探 (六)--- call()和apply()初探

    在javascript中,每个函数都具有call()和apply()两个方法,您可以用她们来触发函数,并指定相关的调用参数. 此外,这两个方法还有另一个功能,就是她可以让一个对象去‘借用‘另一个对象的 ...

  3. Xcode: This device is no longer connected error

    Quit the xcode and connect again will all right.

  4. openfire Android学习(三)----会议室创建、加入以及查询会议室中所有成员等

    openfire 中的会议室不像QQ群一样,不能保存那些离线用户,加入会议室后,一旦断开连接,就会离开会议室. 虽然如此,但如果要实现也不是不可能,我们可以自己做后台来保存,有兴趣的可以去试着实现一下 ...

  5. 记Weblogic采用RAC方式链接数据库遇到的问题

      前几天,去客户现场部署系统,WEBLOGIC连接数据库使用RAC方式连接,好几个人弄了一下午愣是没搞定,总是报SID错误 开始一致认为是防火墙的原因,后来SSH登陆应用服务器后,再TELNET数据 ...

  6. 使用Cout输出String和CString对象

    CString和string都是一个类,不同的是CString主要用于MFC或者是ATL编程中,而string则多用于Windows控制台编程中 在实际编程过程中,我们经常用到string或者是CSt ...

  7. asp.net MVC通用分页组件 使用方便 通用性强

    asp.net MVC通用分页组件 使用方便 通用性强   该分页控件的显示逻辑: 1 当前页面反色突出显示,链接不可点击 2 第一页时首页链接不可点击 3 最后一页时尾页链接不可点击 4 当前页面左 ...

  8. Windows 7 &amp; Ubuntu 14.04完美双系统安装及系统引导配置----校园网Mentohust配置

    本文写于完美安装双系统之后,所以图片会不全然.主要目的是总结下注意事项.备用. 一.Win7-64-旗舰版U盘安装 win7-64-旗舰版纯净版下载,下载安装后仅仅有1个驱动人生! 附刻盘工具激活工具 ...

  9. 李洪强iOS开发之 - 项目架构

    李洪强iOS开发之 - 项目架构 01 - 在Appdelegate中设置跟控制器 //导入头文件

  10. 数据库中表的复杂查询&amp;分页

    一.数据库中表的复杂查询 1)连接查询 1.0连接的基本的语法格式: from TABLE1 join_type TABLE2 [on (join_condition)][where (query_c ...