【bzoj4926】皮皮妖的递推

2024-01-06 08:20
文章标签 递推 皮皮 bzoj4926

本文主要是介绍【bzoj4926】皮皮妖的递推,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

YOUSIKI学习了递推,于是他请皮皮妖给他出道题,皮皮妖说:
f(1)=1,f(i)=i-f(i-1),求f(n)
YOUSIKI看了一眼把它秒切了,于是他要求皮皮妖加大难度,皮皮妖想了想,说:
f(1)=1,f(i)=i-f(f(i-1)),求f(n)
YOUSIKI看了两眼把它秒切了,于是他要求皮皮妖加大难度,皮皮妖想了想,说:
f(1)=1,f(i)=i-f(f(f(i-1))),求f(n)
YOUSIKI看了三眼把它秒切了,于是他要求皮皮妖加大难度,皮皮妖想了想,说:
...
...
...
YOUSIKI看了m眼,但是没有能秒切,于是他找到你,请你帮他解决这个问题。

 

输入

一行两个正整数n,m。n<=10^18,m<=10^6


输出

一行一个整数f(n)


样例输入

4 2


样例输出

3

 



题解

这里简化下题意:定义fn( x )=f( fn-1( x ) ),已知f(1)=1,且对于i>1有 f(i)=i - fm(i-1),求 f(n)。

 

先考虑m=1:f(i) = i-f(i-1),打个表,发现这就是当n为偶数时除以2,n为奇数时+1除以2。

然后当m=2时:f(i)=i-f(f(i-1)),先打表,如果f(i)=k,就把k向 i 连边,那么我们就得到了一棵树,如下图:

容易发现,从第二层开始,每层的个数构成了斐波拉契数列,并且这里有个很难发现的性质,对于每个结点,它的值一定可以表示成几个斐波拉契数之和,将这些斐波拉契数在斐波拉契数列里向后移动一个,然后这些数之和就是这个结点的儿子结点的值,换句话说,把一个结点 i 贪心的从大往小拆成几个斐波拉契数,再把这些数在斐波拉契数列里向前移动一个,就得到了f(i)的答案。

例如:结点16可以拆成13+3,往前移动一位就是8+2=10,所以f(16)=10。于是m=2就解决了。

我们将上面的规律推广,得到一个类斐波拉契数列:f(i) = f(i-1)+f(i-m) ,那么将n分解为几个类斐波拉契数的和,再将这些数在这个类斐波拉契数列里向前移动一位,加起来即为答案。

 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long longll n,m,x,t;
ll f[5000000],ans,a[5000000];void fj(){for(int i=1;;i++)if(f[i]>n) {a[++t]=f[i-1-1];n-=f[i-1];break;}
}int main(){cin>>n>>m;f[0]=1;for(int i=1;i<=m;i++) f[i]=1;for(int i=m+1;;i++){f[i]=f[i-1]+f[i-m];if(f[i]>n){x=i-1; break;}} a[++t]=f[x-1];n-=f[x];while(n) fj();for(int i=1;i<=t;i++) ans+=a[i];cout<<ans;return 0;
}

 

转载于:https://www.cnblogs.com/rlddd/p/9679615.html

这篇关于【bzoj4926】皮皮妖的递推的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/575760

相关文章

uva 568 Just the Facts(n!打表递推)

题意是求n!的末尾第一个不为0的数字。 不用大数,特别的处理。 代码: #include <stdio.h>const int maxn = 10000 + 1;int f[maxn];int main(){#ifdef LOCALfreopen("in.txt", "r", stdin);#endif // LOCALf[0] = 1;for (int i = 1; i <=

HLJUOJ1128 HDU2046(数学递推)

1128: 递推求解专题练习三 Time Limit: 1 Sec   Memory Limit: 128 MB Submit: 8   Solved: 6 [ Submit][ Status][ Web Board] Description 在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数。 例如n=3时,为2× 3方格,骨牌的铺放方案有三

【递推】【DP】-HDU-2064-汉诺塔③

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2064 题目描述:从最左边移到最右边柱子的过程中必须经过中间柱子。 解题思路: 进ACM组时候的考试题,当时虐我的题终于被我虐回来了。。一眼看出方程,1A了。。。呵呵。。满足一下我的虚荣心,,,抚慰一下受挫的心灵吧。 AC代码: #include <iostream>using names

【递推】【DP】-HDU-1996-汉诺塔⑥

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1996 题目描述:问三个柱子上放N个盘子,一共可能有多少种组合?(可以有柱子不放,放的时候依然满足下面盘子比上面盘子大) 解题思路: 对于放N个盘子,ans [ N ] = 3 + 6 * f ( N ) +6 * g ( N ) 这三项依次代表这N个盘子分成一堆,两堆,三堆时有多少种可能。排列

【递推】【DP】-HDU-1995-汉诺塔⑤

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1995 题目描述:计算汉诺塔中某个盘子的移动次数 解题思路: 想了好久,突然顿悟! 思路如下,所谓递推,即是前者与后者存在直接联系,由前者可以直接推出后者,因此必须有一端是已知的,这题里显然最下面的盘子只被动了一次,这就是开端,然后我们考虑紧挨着的两张盘子的递推关系,发现上面盘子是紧挨着的下面盘

【递推】【DP】-HDU-1207-汉诺塔②

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1207 题目描述:四柱汉诺塔 解题思路: 开始想了方程 f [ n ] = 2 * f [n - 2] + 3和 f [ n ] = 2 * f [n - 3] + 7。结果都不对,很郁闷,纠结半天之后,上网查攻略去了,啊!我就差一点了,但也是差了最为关键的一步! 正确的方程应该是: f [

蓝桥杯备赛day02:递推

斐波那契数列 #include <bits/stdc++.h>using namespace std;int main(){int n;cin>>n;int dp[n+1];dp[1]=1;dp[2]=1;for(int i = 3;i <= n;i++) dp[i] = dp[i-1]+dp[i-2];cout<<dp[n];return 0;} n = int(input())

递推—杭电2044 一只小蜜蜂...

http://acm.hdu.edu.cn/showproblem.php?pid=2044 一只小蜜蜂... Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 35811    Accepted Submission(s): 1317

数位dp n内1的个数递推找规律

1061:数字统计 查看提交统计提问 总时间限制:  1000ms  内存限制:  10000kB 描述 给出一个整数n(1<=n<=20000000),要求输出从1到n间所有数字中“1”的出现次数.例如:数字11,1到11间数字“1”的出现次数为4。(1,10,11,11出现4次,因为11有两个1,所以出现4次) 输入 一个整数n,(1<=n<=20000000)

C++编程-递推算法3

目录 先言 回顾 递推算法2 先言 一:平面分割问题 二:汉诺塔 后言 关于递推 后言 先言 本期是递推算法的最后一期了,今天主要解答上期的2个代码,并向大家说一下递推的最后几个注意点 回顾 递推算法2 先言 在上期中,我们讲解了递推算法的最后一道例题和递推关系,并留下了2道练习,本期就来解答 一:平面分割问题 #include<iostream>usi