HDU 4518
整理一下思路,明天再写。。。
这道题,其实就是求包含大于10的斐波那切数字的第K(K是斐波那契数)个数。注意到斐波那契数的爆炸性增长,所以在范围 内的符合要求的F数并不多吧。比如求第K个F数,那么,前K个F数都是这样的数,组成它们的数字中有斐波那契数。这就是字符串匹配吧。把这些数转化成字符串匹配,也就是很经典的数位DP,求范围内含有这些数字的数有多少个。
但是,所要含的数有很多个,怎么样匹配呢?转化成字符串,构成AC自动机来做。但是,说实话,求含有数字的个数确实不好弄,没关系,把它转化成不含有就容易了。于是,就成了AC自动机+数位DP了。但是,我们要求的是第K个,那么,因为个数是单调增的,求出刚好第K个可以使用二分查找来办到。
使用AC自动机来做数位DP,首先要构建trie图,然后明白哪些状态是可转移或不可转移的,然后在trie图上进行DP就可以了。
dp[i][j],即是当前是前第i位数位,并处在自动机的j状态上。
#include <iostream>
#include <cstdio>
#define LL __int64
using namespace std; const LL inf=10000000000000ll;
const int root=;
LL f[],ans[]; int trie[][],bit[],fail[],que[],head,tail;
int tot;
int nxt[][];
LL dp[][];
bool tag[]; void insert(LL now){
int len=;
while(now){
bit[++len]=now%;
now/=;
}
int p=root,i=len;
while(i--){
if(trie[p][bit[i+]]==-){
trie[p][bit[i+]]=++tot;
}
p=trie[p][bit[i+]];
}
tag[p]=true;
} void build_ac(){
head=tail=;
que[tail++]=root;
while(head!=tail){
int tmp=que[head++];
int p=-;
for(int i=;i<;i++){
if(trie[tmp][i]!=-){
if(tmp==root) fail[trie[tmp][i]]=root;
else{
p=fail[tmp];
while(p!=-){
if(trie[p][i]!=-){
fail[trie[tmp][i]]=trie[p][i];
break;
}
p=fail[p];
}
if(p==-) fail[trie[tmp][i]]=root;
}
if(tag[fail[trie[tmp][i]]]) tag[trie[tmp][i]]=tag[fail[trie[tmp][i]]];
que[tail++]=trie[tmp][i];
}
else{
if(tmp==root) trie[tmp][i]=root;
else{
p=fail[tmp];
while(p!=-){
if(trie[p][i]!=-){
trie[tmp][i]=trie[p][i];
break;
}
p=fail[p];
}
if(p==-) trie[tmp][i]=root;
}
}
}
}
} LL dfs(int len,int j,bool flag){
if(len==) return 1ll;
if(!flag&&dp[len][j]!=-) return dp[len][j];
LL ans=;
int up=flag?bit[len]:;
for(int i=;i<=up;i++){
if(tag[nxt[j][i]]||nxt[j][i]==-) continue;
ans+=dfs(len-,nxt[j][i],i==up&&flag);
}
if(!flag) dp[len][j]=ans;
return ans;
} LL cal(LL m){
LL tm=m+1ll;
int len=;
while(m){
bit[++len]=m%;
m/=;
}
return tm-dfs(len,,true);
// return 0;
} LL bin(LL num){
// cout<<cal(13)<<endl;
// system("pause");
LL l=,r=inf,ret=-,tmp;
while(l<=r){
LL m=(l+r)>>;
if((tmp=cal(m))>=num){
r=m-;
ret=m;
// cout<<m<<endl;
}
else l=m+;
}
return ret;
} int cal_next(int p,int j){
if(tag[p]) return -;
if(tag[trie[p][j]]) return -;
return trie[p][j];
} void Init(){
tot=;
memset(trie,-,sizeof(trie));
memset(tag,false,sizeof(tag));
memset(fail,-,sizeof(fail));
f[]=1ll; f[]=1ll;
for(int i=;i<=;i++){
f[i]=f[i-]+f[i-];
if(f[i]>){
insert(f[i]);
}
}
build_ac();
for(int i=;i<=tot;i++){
for(int j=;j<;j++)
nxt[i][j]=cal_next(i,j);
}
memset(dp,-,sizeof(dp));
int c=;
for(int i=;i<=;i++){
ans[c]=bin(f[i]);
// system("pause");
if(ans[c]==-) break;
c++;
// printf("%I64d %d\n",ans[c-1],c);
}
} int main(){
Init();
LL n;
// cout<<"YES"<<endl;
while(scanf("%I64d",&n)!=EOF&&n!=-){
LL ret=inf;
for(int i=;i<;i++){
LL tmp=n-ans[i];
// cout<<tmp<<endl;
if(tmp<) tmp=-tmp;
if(ret>tmp) ret=tmp;
}
printf("%I64d\n",ret);
}
return ;
}
HDU 4518的更多相关文章
- HDOJ 2111. Saving HDU 贪心 结构体排序
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 【HDU 3037】Saving Beans Lucas定理模板
http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...
- hdu 4859 海岸线 Bestcoder Round 1
http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...
- HDU 4569 Special equations(取模)
Special equations Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u S ...
- HDU 4006The kth great number(K大数 +小顶堆)
The kth great number Time Limit:1000MS Memory Limit:65768KB 64bit IO Format:%I64d & %I64 ...
- HDU 1796How many integers can you find(容斥原理)
How many integers can you find Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d ...
- hdu 4481 Time travel(高斯求期望)(转)
(转)http://blog.csdn.net/u013081425/article/details/39240021 http://acm.hdu.edu.cn/showproblem.php?pi ...
- HDU 3791二叉搜索树解题(解题报告)
1.题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3791 2.参考解题 http://blog.csdn.net/u013447865/articl ...
- hdu 4329
problem:http://acm.hdu.edu.cn/showproblem.php?pid=4329 题意:模拟 a. p(r)= R'/i rel(r)=(1||0) R ...
随机推荐
- 利用存储过程插入50W+数据
转自:https://www.aliyun.com/jiaocheng/1396184.html 首先,建立部门表和员工表: 部门表: create table dept( id int un ...
- PCB C# 连接MongoDB 数据库
一.C# MongoDB 驱动下载 1.百度网盘:nuget下载地址(V2.7版本) https://pan.baidu.com/s/1VDsVcH1TMrXqhRCZVewZgA 2.VS 中NUg ...
- E20170915-hm
client n. 顾客; 当事人; 诉讼委托人; [计算机] 客户端; seal n. 密封; 印章; 海豹; 封条; v. 密封; 盖章; 决定; 封上(信封); sheet n. 纸; 被 ...
- 用xftp从win7系统传输一些必要的文件到Linux
新建会话,主机名为Linux系统的ip地址,选用SFTP协议,选用UTF-8编码格式 1.安装JDK 切换到java路径下 卸载openJDK: 用rpm -qa |grep java指令查看 用rp ...
- jar 包中文乱码注释显示问题解决方案
通过maven下载源代码,直接通过eclipse浏览源代码时,发现中文注释为乱码的问题.其实这个eclipse默认编码造成的问题.可以通过以下方法解决: 修改Eclipse中文本文件的默认编码:win ...
- es优化收藏
Elasticsearch常用优化 https://www.cnblogs.com/zlslch/p/6478773.html Elasticsearch 基础理论 & 配置调优 http:/ ...
- 终极解决VS2015 安装失败问题,如 安装包损坏或丢失
1.去微软官网下载完成ISO镜像,最好不要在线安装, 打开官方链接 https://www.visualstudio.com/zh-cn/downloads/download-visual-studi ...
- OpenCV:OpenCV图像旋转的代码
OpenCV图像旋转的代码 cv::transpose( bfM, bfM ) 前提:使用两个矩阵Mat型进行下标操作是不行的,耗费的时间太长了.直接使用两个指针对拷贝才是王道.不知道和OpenCV比 ...
- Java语言输出HelloWorld
1.新建一个名为HelloWorld.txt的文本文件. 2.将HelloWorld.txt改为.java. 3.将HelloWorld.java用文本文件的方式打开,并输入代码. 4.打开命令行,进 ...
- 绝对好用的浏览器json解析网址
你们是否经常在浏览器输入请求地址解析遇到中文乱码的情况,今天我找到了一个好用的浏览器解析json网址,绝对好用. 1.直接输入网址 http://pro.jsonlint.com/ 2.输入要解析的j ...