~~~题面~~~

思路:

主要难点在思路的转化,

不能看见要求$\sum{a[i]^2}$就想着求a[i],

我们可以对其进行某种意义上的拆分,即a[i]实际上可以代表什么?

假设我们现在有两种取出某一数列的方法,分别为X,Y。(X,Y可以相同)

那么这样的二元组有多少个呢?

a[i]^2个。

因为X的取法有a[i]种,Y的取法也是a[i]种,所以二元组个数实际上就是a[i]^2.

那么这样一转化有什么好处?

方便DP

因为这样的话就不在需要知道具体的a[i]了,因为二元组的个数是可以拆开来算的,

所以就可以考虑递推/DP了。

我们用f[i][j][k][l]表示第一种决策X在上面取了i个,下面取了j个,第二种决策Y在上面取了k个,在下面取了l个且产生序列相同的二元组个数

显然一开始的f[0][0][0][0]要设为1,

然后注意到我们应该要同步取,不然个数都不同,序列也不可能相同了,

因此我们数组中就可只存3维了,因为第4维可以通过i + j - k得到。

那么应该如何转移呢?

假设现在我们有f[i][j][k],显然要使下一次取出来的序列相同,只要让下一次取的珠子一样就可以了,因为其他部分现在已经一样了,

因此我们就可以分别枚举X取上面,X取下面,Y取上面,Y取下面,然后相互搭配,一共4种情况,如果满足下一次取的珠子一样就可以转移,

因为n有500,所以空间还是承受不了,观察到i的转移只涉及到i和i+1,因此我们可以用滚动数组优化。

但是我们注意到用f[i][j][k]向f[i+1][j][k+1]这类的转移的话,如果不及时清空,因为使用的是滚动数组,转移的时候又是+=,无法将原来的答案覆盖,

那就会重复统计,因此我们不能向前转移,我们应该要枚举当前状态,枚举向当前状态转移的状态,并且每次转移之前要清空数组,这样就可以了

注意将不合法的状态减掉,luogu上这题貌似有点卡常,,,

work1是另一种状态表示方法,,,我也不知道为什么比work快

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 510
#define mod 1024523
/*转化为有序数对的统计之后就可以不用在意具体数列到底是什么样的了,因为只要相同就可以了,
但是由于是同步取的,所以两种决策取的次数是相同的,所以少掉一维是没关系的,
因为剩下那维可以直接推出来,是没用的*/
int n,m,now;
int f[][AC][AC];
char U[AC],D[AC];
void pre()
{
scanf("%d%d",&n, &m);
scanf("%s", U + );
scanf("%s", D + );
reverse(U+,U+n+);
reverse(D+,D+m+);//因为是从右边开始取的,所以要反过来!!!
} inline void update(int &a,int b)
{
a += b;
if(a > mod) a -= mod;
}
//本来是向前做贡献,但是这样贡献会和前面的累加,
//所以需要在做的过程中初始化,但这样就不太好掌控什么时候初始化,
//因此改成从前面取贡献,方便初始化,但是这样的话前面的判断就要麻烦点了
void work()
{
f[now][][] = ;//一开始啥也没取,,,
for(R i=;i<=n;i++)//可以取0个啊
{
for(R j=;j<=m;j++)
for(R k=;k<=n;k++)
{
if(!i && !j) continue;//这个不能初始化掉了
if(i + j - k > m) continue;//因为i,j,k枚举了,所以肯定合法,但最后一个要计算得到,不一定合法
f[now][j][k] = ;//初始化,防止叠加
if(i && k && U[i] == U[k]) update(f[now][j][k],f[now^][j][k-]);
if(i && i + j - k && U[i] == D[i + j - k]) update(f[now][j][k],f[now^][j][k]);
if(j && k && D[j] == U[k]) update(f[now][j][k],f[now][j-][k-]);
if(j && i + j - k && D[j] == D[i + j - k]) update(f[now][j][k],f[now][j-][k]);
// printf("%d %d %d = %d\n",i,j,k,f[now][j][k]);
}
now ^= ;
}
printf("%d\n",f[now^][m][n]);
printf("time used ... %lf\n",(double)clock()/CLOCKS_PER_SEC);
} void work1()
{//现在取了i个,第一种决策在第一行取了j个,第二种取了k个
f[][][] = ;//因为是滚了一维
int b = n + m;
for(R i = ; i <= b; i++)
{
int lim = min(i, n);
for(R j = ; j <= lim; j++)
{
for(R k = ; k <= lim; k++)
{
int x = i - j, y = i - k;//x为第一种决策在第二行取的,y则是第二种决策
if(x > m || y > m) continue;
f[now][j][k] = ;
if(j && U[j] == U[k]) update(f[now][j][k], f[now^][j-][k-]);
if(j && U[j] == D[y]) update(f[now][j][k], f[now^][j-][k]);
if(x && D[x] == U[k]) update(f[now][j][k], f[now^][j][k-]);
if(x && D[x] == D[y]) update(f[now][j][k], f[now^][j][k]);
// printf("%d %d %d = %d\n",i,j,k,f[now][j][k]);
}
}
now ^= ;
}
printf("%d\n",f[now^][n][n]);
// printf("time used ... %lf\n",(double)clock()/CLOCKS_PER_SEC);
} int main()
{
//freopen("in.in","r",stdin);
pre();
//work();
work1();
//fclose(stdin);
return ;
}

[NOI2009]管道取珠 DP + 递推的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. NOI2009 管道取珠 神仙DP

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

  7. BZOJ 1566 管道取珠(DP)

    求方案数的平方之和.这个看起来很难解决.如果转化为求方案数的有序对的个数.那么就相当于求A和B同时取,最后序列一样的种数. 令dp[i][j][k]表示A在上管道取了i个,下管道取了j个,B在上管道取 ...

  8. 【题解】NOI2009管道取珠

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

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

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

随机推荐

  1. 创龙DSP6748开发板LED闪烁-第一篇

    1. 首先看下DSP6748的GPIO寄存器的文档,先看下框图,有这个框图,一目了然,输入和输出很清楚 2. 看下寄存器部分,对应上面的图,问题在于,DSP6748有多少个GPIO?最多144个,下一 ...

  2. XSS--编码绕过,qcms,鲶鱼cms

    一.编码绕过 1)HTML进制编码 标签中的某些属性值可以使用html十进制.十六进制表示 2)JavaScript编码 JavaScript支持unicode.八进制.十六进制.十进制等 3)URL ...

  3. mysql新手进阶02

    云想衣裳花想容,春风拂槛露华浓. 若非群玉山头见,会向瑶台月下逢. 现在有一教学管理系统,具体的关系模式如下: Student (no, name, sex, birthday, class) Tea ...

  4. 如何搭建本地svn服务器和搭建本地Git服务器

    搭建git本地服务器使用的软件有很多,例如:gitlab,gitblit,gitbucket,gogs,gitolite,具体比较:http://softlab.sdut.edu.cn/blog/su ...

  5. TW实习日记:第27天

    今天依旧是磨洋工的一天,说真的,被存在各种问题的后端接口把耐心和动力都给磨没了.于是一天就又在沟通接口问题中度过了,完善了一个新功能,将一个新功能开发到了一半.效率可真是够低的,唉.然后不知道为什么突 ...

  6. lintcode142 O(1)时间检测2的幂次

    O(1)时间检测2的幂次 用 O(1) 时间检测整数 n 是否是 2 的幂次. 您在真实的面试中是否遇到过这个题? Yes 样例 n=4,返回 true; n=5,返回 false. 二进制的n中只有 ...

  7. org.apache.spark.launcher.Main源码分析

    public static void main(String[] argsArray) throws Exception { //org.apache.spark.launcher.Main chec ...

  8. 机器学习-聚类Clustering

    简介 前面介绍的线性回归,SVM等模型都是基于数据有标签的监督学习方法,本文介绍的聚类方法是属于无标签的无监督学习方法.其他常见的无监督学习还有密度估计,异常检测等. 聚类就是对大量未知标注的数据集, ...

  9. LeetCode 240——搜索二维矩阵 II

    1. 题目 2. 解答 2.1. 方法一 从矩阵的左下角开始比较 目标值等于当前元素,返回 true: 目标值大于当前元素,j 增 1,向右查找,排除掉此列上边的数据(都比当前元素更小): 目标值小于 ...

  10. hexo设置permalink-避免url中出现中文

    hexo博客初始化的url是年月日+题目:year/:month/:day/:title/,这样的url不便与分享,中文会乱吗,而且一旦修改了题目(我相信大部分人的题目都是中文)就会导致之前分享的ur ...