ZOJ 2672 Fibonacci Subsequence(动态规划+hash)
题意:在给定的数组里,寻找一个最长的序列,满足ai-2+ai-1=ai。并输出这个序列。
很容易想到一个DP方程
dp[i][j]=max(dp[k][i])+1. (a[k]+a[i]==a[j],1<=k&&k<i)
dp[i][j]表示序列最后两位是a[i],a[j]时的最长长度。
这个方程状态是O(n^2),转移是O(n),总复杂度是O(n^3)会超时。
进一步思考会发现转移这里是可以优化的。实际上我们只需要知道离i最近的那个满足a[k]+a[i]==a[j]的k就行,即最大k。
举个例子
2 3 -1 2 1 3
当i=5,j=6,即ai=1,aj=3时,这时需要找一个ak=2的,显然a1和a4满足,我们会选择a4而不是a1。因为可以转移到a1的状态一定都可以转移到a1,但能转移到a4的状态却不一定都能转移到a1,因此dp[4][5]>=dp[1][5]。这样我们只需要在遍历数组的时候维护数组每个数的最大的下标即可。这里使用hash来做。
我用了stl的hash_map。最后需要逆序输出结果。另外注意卡内存,要用short。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<hash_map>
#include<ext/hash_map>
using namespace std;
using __gnu_cxx::hash_map;
hash_map <int,short> has;
];
][];
void output(int n,int x,int y)
{
if(!n) return ;
output(n-,y-x,x);
) printf("%d",y-x);
else printf(" %d",y-x);
}
int main()
{
int n;
bool blank=false;
while(scanf("%d",&n)!=EOF)
{
if(blank) printf("\n");
else blank=true;
memset(dp,,sizeof(dp));
; i<=n; ++i)
{
scanf("%d",&a[i]);
; j<i; ++j)
dp[j][i]=;
}
)
{
printf(]);
continue;
}
has.clear();
,x=a[],y=a[];
; i<=n; ++i)
{
; j<=n; ++j)
{
hash_map<int,short>::iterator it=has.find(a[j]-a[i]);
if(it!=has.end())
dp[i][j]=dp[it->second][i]+;
if(dp[i][j]>ans)
{
ans=dp[i][j];
x=a[i];
y=a[j];
}
}
has[a[i]]=i;
}
printf("%d\n",ans);
ans-=;
output(ans,x,y);
if(ans) printf(" ");
printf("%d %d\n",x,y);
}
;
}
当然也可以定义状态 dp[i][j]为序列开头两个数字是ai,aj的最长长度。这样就可以正序输出了。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<hash_map>
#include<ext/hash_map>
using namespace std;
using __gnu_cxx::hash_map;
hash_map <int,short> has;
];
][];
int main()
{
int n;
bool blank=false;
while(scanf("%d",&n)!=EOF)
{
if(blank) printf("\n");
else blank=true;
memset(dp,,sizeof(dp));
; i<=n; ++i)
{
scanf("%d",&a[i]);
; j<=n; ++j)
dp[i][j]=;
}
has.clear();
,x=a[],y;
; --i)
{
; j>=; --j)
{
hash_map<int,short>::iterator it=has.find(a[i]+a[j]);
if(it!=has.end())
{
dp[j][i]=dp[i][it->second]+;
}
if(ans<dp[j][i])
{
ans=dp[j][i];
x=a[j];
y=a[i];
}
}
has[a[i]]=i;
}
ans++;
printf("%d\n",ans);
printf("%d",x);
; i<=ans; ++i)
{
printf(" %d",y);
int t=y;
y=x+y;
x=t;
}
printf("\n");
}
;
}
下面是自己实现的hash。
这个用绝对值取模的hash函数。跑了4s+。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
];
][];
pair<];
static const int mask=0x7fff;
void init()
{
; i<=mask; ++i) has[i].first=-;
}
int find(int x)
{
int key=abs(x)%mask;
while(has[key].first!=x)
{
)
;
key=(key+)%mask;
}
return has[key].second;
}
void insert(int x,int val)
{
int key=abs(x)%mask;
)
{
if(has[key].first==x)
{
has[key].second=val;
return ;
}
key=(key+)%mask;
}
has[key].first=x;
has[key].second=val;
}
int main()
{
int n;
bool blank=false;
while(scanf("%d",&n)!=EOF)
{
if(blank) printf("\n");
else blank=true;
memset(dp,,sizeof(dp));
init();
; i<=n; ++i)
{
scanf("%d",&a[i]);
; j<=n; ++j)
dp[i][j]=;
}
,x=a[],y;
; --i)
{
; j>=; --j)
{
int it=find(a[i]+a[j]);
)
{
dp[j][i]=dp[i][it]+;
}
if(ans<dp[j][i])
{
ans=dp[j][i];
x=a[j];
y=a[i];
}
}
insert(a[i],i);
}
ans++;
printf("%d\n",ans);
printf("%d",x);
; i<=ans; ++i)
{
printf(" %d",y);
int t=y;
y=x+y;
x=t;
}
printf("\n");
}
;
}
这个是用&的hash函数。跑了1s+。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<hash_map>
#include<ext/hash_map>
using namespace std;
];
][];
pair<];
static const int mask=0x7fff;
int Hash(int val)
{
return val&mask;
}
void init()
{
; i<=mask; ++i) has[i].first=-;
}
int find(int x)
{
int key=x&mask;
while(has[key].first!=x)
{
)
;
key=(key+)&mask;
}
return has[key].second;
}
void insert(int x,int val)
{
int key=x&mask;
)
{
if(has[key].first==x)
{
has[key].second=val;
return ;
}
key=(key+)&mask;
}
has[key].first=x;
has[key].second=val;
}
int main()
{
int n;
bool blank=false;
while(scanf("%d",&n)!=EOF)
{
if(blank) printf("\n");
else blank=true;
memset(dp,,sizeof(dp));
init();
; i<=n; ++i)
{
scanf("%d",&a[i]);
; j<=n; ++j)
dp[i][j]=;
}
,x=a[],y;
; --i)
{
; j>=; --j)
{
int it=find(a[i]+a[j]);
)
{
dp[j][i]=dp[i][it]+;
}
if(ans<dp[j][i])
{
ans=dp[j][i];
x=a[j];
y=a[i];
}
}
insert(a[i],i);
}
ans++;
printf("%d\n",ans);
printf("%d",x);
; i<=ans; ++i)
{
printf(" %d",y);
int t=y;
y=x+y;
x=t;
}
printf("\n");
}
;
}
最后这个是watash写的hash_map。跑了1s+。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<hash_map>
#include<ext/hash_map>
using namespace std;
];
][];
struct Hash
{
static const int mask = 0x7fff;
], q[];
void clear()
{
; i <= mask; ++i)
q[i] = -;
}
int& operator[](int k)
{
int i = k & mask;
&& p[i] != k; i = (i + ) & mask);
p[i] = k;
return q[i];
}
} hash;
int main()
{
int n;
bool blank=false;
while(scanf("%d",&n)!=EOF)
{
if(blank) printf("\n");
else blank=true;
memset(dp,,sizeof(dp));
hash.clear();
; i<=n; ++i)
{
scanf("%d",&a[i]);
; j<=n; ++j)
dp[i][j]=;
}
,x=a[],y;
; --i)
{
; j>=; --j)
{
int it=hash[a[i]+a[j]];
)
{
dp[j][i]=dp[i][it]+;
}
if(ans<dp[j][i])
{
ans=dp[j][i];
x=a[j];
y=a[i];
}
}
hash[a[i]]=i;
}
ans++;
printf("%d\n",ans);
printf("%d",x);
; i<=ans; ++i)
{
printf(" %d",y);
int t=y;
y=x+y;
x=t;
}
printf("\n");
}
;
}
ZOJ 2672 Fibonacci Subsequence(动态规划+hash)的更多相关文章
- ZOJ 2723 Semi-Prime ||ZOJ 2060 Fibonacci Again 水水水!
两题水题: 1.如果一个数能被分解为两个素数的乘积,则称为Semi-Prime,给你一个数,让你判断是不是Semi-Prime数. 2.定义F(0) = 7, F(1) = 11, F(n) = F( ...
- LC 873. Length of Longest Fibonacci Subsequence
A sequence X_1, X_2, ..., X_n is fibonacci-like if: n >= 3 X_i + X_{i+1} = X_{i+2} for all i + 2 ...
- 【LeetCode】873. Length of Longest Fibonacci Subsequence 解题报告(Python)
[LeetCode]873. Length of Longest Fibonacci Subsequence 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: ...
- ZOJ 3349 Special Subsequence
Special Subsequence Time Limit: 5000ms Memory Limit: 32768KB This problem will be judged on ZJU. Ori ...
- HDOJ 1423 Greatest Common Increasing Subsequence -- 动态规划
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1423 Problem Description This is a problem from ZOJ 2 ...
- HDU 1159 Common Subsequence 动态规划
2017-08-06 15:41:04 writer:pprp 刚开始学dp,集训的讲的很难,但是还是得自己看,从简单到难,慢慢来(如果哪里有错误欢迎各位大佬指正) 题意如下: 给两个字符串,找到其中 ...
- LeetCode 873. Length of Longest Fibonacci Subsequence
原题链接在这里:https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/ 题目: A sequence X_1, X ...
- 斐波那契数列Fibonacci问题—动态规划
斐波那契数列定义 Fibonacci array:1,1,2,3,5,8,13,21,34,... 在数学上,斐波那契数列是以递归的方法来定义: F(0) = 0 F(1) = 1 F(n) = F( ...
- hdu1159Common Subsequence——动态规划(最长公共子序列(LCS))
Problem Description A subsequence of a given sequence is the given sequence with some elements (poss ...
随机推荐
- 显示win7桌面网络.reg
显示win7桌面网络.reg Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\C ...
- Shader中贴图知识汇总: 漫反射贴图、凹凸贴图、高光贴图、 AO贴图、环境贴图、 光照纹理及细节贴图
原文过于冗余,精读后做了部分简化与测试实践,原文地址:http://www.j2megame.com/html/xwzx/ty/2571.html http://www.cnblogs.com/z ...
- 获取本机 Android 默认sha1 秘钥
获取本机 Android 默认sha1 秘钥: 以Windows操作系统为例,打开CMD,运行以下指令将得到所有默认秘钥. keytool -list -v -keystore C:\Users\pa ...
- 转 http://www.5icool.org/a/201106/a654.html CSS开发中常用的公用样式
overflow:hidden 隐藏溢出 一.自己总结的公用样式解析 html, body, div, p, ul, li, dl, dt, dd, h1, h2, h3, h4, h5, h6, f ...
- python 循环设计
for循环 1.range()用法 for循环后的in跟随一个序列的画,循环每次使用的序列元素而不是序列的下标 例:s='abcdefg' for i in range(0,len(s),3): pr ...
- .NET GC机制学习笔记
学习笔记内容来自网络资料摘录http://www.cnblogs.com/springyangwc/archive/2011/06/13/2080149.html 1.GC介绍 Garbage Col ...
- WPF布局的6种面板
WPF用于布局的面板主要有6个,StackPanel(栈面板).WrapPanel(环绕面板).DockPanel(停靠面板).Canvas(画布).Grid(网格面板)和 UniformGrid(均 ...
- jquery $post $get $
Jquery在异步提交方面封装的很好,直接用AJAX非常麻烦,Jquery大大简化了我们的操作,不用考虑浏览器的诧异了. 推荐一篇不错的jQuery Ajax 实例文章,忘记了可以去看看,地址为:ht ...
- 使用openssl库实现RSA、AES数据加密
openssl是可以很方便加密解密的库,可以使用它来对需要在网络中传输的数据加密.可以使用非对称加密:公钥加密,私钥解密.openssl提供了对RSA的支持,但RSA存在计算效率低的问题,所 ...
- 目前几款基于html5的前端框架:如Bootstrap、Foundation、Semantic UI 、Amaze UI
Bootstrap是由Twitter在2011年8月推出的开源WEB前端框架,集合CSS 和HTML,使用了最新的浏览器技术,为快速WEB开发提供了一套前端工具包,包括布局.网格.表格.按钮.表单.导 ...