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 ...
随机推荐
- php 使用 restler 框架构建 restfull api
php 使用 restler 框架构建 restfull api restler 轻量级,小巧,构建restfull api非常方便! 官网:http://restler3.luracast.com/ ...
- redis订阅发布
一.简介 Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订 ...
- Computer assembly and maintenance
转载请注明出处: 我所遇见的世界会更美好 第一章 计算机的基本构成和组装 1,内存的组成? (1) RAM(随机存取存储器) (2) ROM(只读存储器) (3) Cache(高速缓存) 2,S ...
- 5.4.1 Selenium2启动空浏览器
在Web自动化测试中,必须考虑不同浏览器对网站的兼容性测试,所以我们首先介绍如何用webDriver代码打开不同的浏览器. 本节介绍的是在Selenium2启动浏览器时,启动一个干净的没有任务插件及c ...
- CSS小结
一.1. css必须写在<head></head>里面的<style></style>里面 2. css 由选择器 + 规则组成, 规则由属性和值组成 ...
- ArcMap上发布地图服务前,“将图形转为要素的选项”时报“输出名称无效”错误
发布ArcMap服务时,由于矢量图中包含“文本标注”. 发布矢量图服务时,报了一个“00017: 数据框中至少有一个包含图形的已启用注记组”的错误,如下图: 官网给出的解决办法如下:http://re ...
- HTML5自学笔记[ 20 ]canvas绘图实例之绘制倒影
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- Qt Charts
简述 Qt Charts模块提供了一套易于使用的图表组件.它采用了Qt Graphics View框架,因此图表可以很容易地集成到现代的用户界面. Qt Charts可以被用作QWidgets.QGr ...
- Redis与Java - 数据结构
Redis与Java 标签 : Java与NoSQL Redis(REmote DIctionary Server) is an open source (BSD licensed), in-memo ...
- javaSE基础——常见的dos命令即其他
常用的DOS命令 dir(directory) : 列出当前目录下的文件以及文件夹 md(make directory) : 创建目录 rd(remove directory) : 删除目录 ...