第二场周赛(递归递推个人Rank赛)——题解
很高兴给大家出题,本次难度低于上一场,新生的六个题都可以直接裸递归式或者裸递推式解决,对于老生的汉诺塔3,需要找出一般式,后两题分别为裸ST算法(或线段树)/线性DP。
正确的难度顺序为
- 种花
- 角谷定律
- 猴子和椰子
- 汉诺塔1
- 汉诺塔2
- 整数划分
- 跳台阶
- 汉诺塔3
- 夏目友人帐(一)
- 夏目友人帐(二)
一、种花
本题很容易能推出递推式或者一般式,对于第一快地,有3种种植方法,对于后面的每一快地有不同于前一块地的两种种植方法。
- a1 = 3;
- an = 2*(an-1);
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[25]; 5 6 void init(){ 7 a[1] = 3; 8 for(int i = 2; i <= 20; i++){ 9 a[i] = a[i-1]*2; 10 } 11 } 12 13 int main(){ 14 freopen("test.out","w",stdout); 15 int n; 16 init(); 17 while(cin>>n){ 18 cout << a[n] << endl; 19 } 20 return 0; 21 }
二、角谷定律
本题按照给出的式子操作即可,用另外一个变量记录操作次数。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int cnt = 0; 5 void fun(long long n){ 6 if(n == 1) 7 return ; 8 if(n&1) 9 cnt++,fun(3*n+1); 10 else 11 cnt++,fun(n/2); 12 } 13 14 int main(){ 15 int n; 16 freopen("test.in","r",stdin); 17 freopen("test.out","w",stdout); 18 while(cin>>n){ 19 cnt = 0; 20 fun(n); 21 cout << cnt << endl; 22 } 23 return 0; 24 }
三、猴子和椰子
可能你们也在其他地方看见过本题,设初始椰子为A,最后一次分给每个人的椰子为n,很容易推得一个A关于n得常数式子,因为要保证能够按照题目分下去,所以要保证每次分椰子都为正整数,已得答案为15621(5^6 - 4)。算是个小学数学题。
输出15621即可。
四、汉诺塔1
这是一个汉诺塔的基本变式,其实用汉诺塔的思想去想也不难,要移动n根木根从A至C,可划分为下面几个步骤。
- 先移动n-1根木根到C
- 移动第n根木棍到B
- 移动C上的n-1根木棍到A
- 移动B上的第n根木棍到C
- 移动A上的n-1根木棍到C
至此,完成这个汉诺塔的移动,我们把移动n根木棍从A到C计为F(n)。
则F(n) = F(n-1) + 1 + F(n-1) + 1 + F(n-1) = 3*F(n-1) + 2;且F(1) = 2;
按照这个步骤写出递归函数即可。代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 long long fun(int n){ 5 if(n == 1) 6 return 2; 7 return 3*fun(n-1)+2; 8 } 9 10 int main(){ 11 freopen("test.in","r",stdin); 12 freopen("test.out","w",stdout); 13 int n; 14 while(cin>>n){ 15 cout << fun(n) << endl; 16 } 17 return 0; 18 }
五、汉诺塔2
在汉诺塔1的基础上多了可以把最长的木棍放在最上面,还是按照上面的步骤,移动n根木棍从A到C可划分为
- 移动n-1根木棍从A到B
- 移动第n根木棍到B上
- 移动第n根木棍到C上
- 移动n-1根木棍从B到C
至此,完成汉诺塔的移动,我们把移动n根木根从A到C计为F(n),移动n根木棍到邻柱子计为T(n),关于T(n)的公式这里就不推了,演变方式一样。
所以有F(n) = T(n-1)+1+1+T(n-1) = 2*T(n-1)+2;且F(1) = 2;
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int fc(int n){ 5 if(n == 1) 6 return 1; 7 return 3*fc(n-1)+1; 8 } 9 10 int fun(int n){ 11 if(n == 1) 12 return 2; 13 return 2*fc(n-1)+2; 14 } 15 16 int main(){ 17 freopen("test.in","r",stdin); 18 freopen("test.out","w",stdout); 19 int n; 20 while(cin>>n){ 21 cout << fun(n) << endl; 22 } 23 return 0; 24 }
六、整数划分
其实这个题题面以及给出了一点提示,把n分成m个正整数的和,要直接求n的划分个数比较难,但是我们可以求n-1、n-2,,,的划分,设n = ΣDi,且max(Di) <= k,
即Di为n的一种划分方案,最大数字不超过k,把它计为F(n,k),那么本题也就是求F(n,n);根据 n,k的不同大小关系,可得下列递归式
- F(n, k) = 1; (n =1 or k = 1)
- F(n, k) = F(n, n); (n < k)
- F(n, k) = F(n, k-1) + 1; (n = k)
- F(n, k) = F(n-k, k) + F(n, k-1); (n > k)
所以可以写出代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int fun(int n,int m){ 5 if(n == 1 || m == 1) 6 return 1; 7 else if(n < m) 8 return fun(n,n); 9 else if(n == m) 10 return fun(n,n-1)+1; 11 else if(n > m) 12 return fun(n,m-1)+fun(n-m,m); 13 } 14 15 int main(){ 16 freopen("test.in","r",stdin); 17 freopen("test.out","w",stdout); 18 int n; 19 while(cin>>n){ 20 cout << fun(n,n) << endl; 21 } 22 cerr << clock() << endl; 23 return 0; 24 }
七、跳台阶
其实很容易推出对于n阶台阶的方案有
F(n) = Σ(F(n-Pi)); (P1 = 1,Pi = 质数集合)
边界条件F(1) = F(0) = 1;
所以代码显而易见了,其实本题还想卡一下数据范围,因为34好像就会爆int,还是算了,就只给你们弄到30,而且本题开了4s,其实我STD只跑了1.7s,奈何只能取整,干脆就4s得了。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int prime[1100],primesize,phi[1100]; 5 bool isprime[1100]; 6 7 int n; 8 9 void getlist(int listsize){ 10 memset(isprime,1,sizeof(isprime)); 11 isprime[1]=false; 12 for(int i=2;i<=listsize;i++) 13 { 14 if(isprime[i])prime[++primesize]=i; 15 for(int j=1;j<=primesize&&i*prime[j]<=listsize;j++) 16 { 17 isprime[i*prime[j]]=false; 18 if(i%prime[j]==0)break; 19 } 20 } 21 prime[0] = 1; 22 } 23 24 int fun(int n){ 25 int sum = 0; 26 if(n == 1 || n == 0) 27 return 1; 28 for(int i = 0; i <= primesize; i++){ 29 if(n < prime[i]) 30 break; 31 sum += fun(n-prime[i]); 32 } 33 return sum; 34 } 35 36 int main(){ 37 freopen("test.in","r",stdin); 38 freopen("test.out","w",stdout); 39 ios_base::sync_with_stdio(false); 40 getlist(100); 41 int n; 42 while(cin>>n){ 43 cout << fun(n) << endl; 44 } 45 cerr << clock() <<endl; 46 }
八、汉诺塔3
四柱汉诺塔问题,我都懒得写如何推了,易得下面递归式
F(n) = min(2*F(n-r)+2r-1),1 <= r <= n;
但是直接用上面式子写递归式肯定会时间爆炸,不信你试试。
最大n不超过100,所以其实你先递推出任意一项就可以了= =,这样的话预处理时间为O(n2),查询时间为O(1)。为了你们好= =所以我没有卡这种算法。
但其实也可以得出一般式,根据Frame-Stewart算法可得出当r = floor((sqrt(8*n+1)-1)/2)时,有最小值,且最小值F(n) = (n - (r2-r+2)/2)*2r+1;
即可以在O(1)时间内得出任意n根木棍需要的最小转移次数。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[105] = {0}; 5 6 int init(){ 7 fill(a,a+101,0x3f3f3f3f); 8 a[0] = 0,a[1] = 1,a[2] = 3; 9 for(int i = 3; i <= 100; i++){ 10 for(int j = 1; j < 32; j++){ 11 temp = 2*a[j]+pow(2LL,(long long)j)-1; 12 a[i] = min(a[i],temp); 13 } 14 } 15 } 16 17 int main(){ 18 freopen("test.in","r",stdin); 19 freopen("test.out","w",stdout); 20 int n; 21 while(cin>>n){ 22 int r = floor((sqrt(8*n+1)-1.0)/2.0); 23 int ans = (n-(r*r-r+2)/2.0)*pow(2.0,r)+1; 24 cout << ans << endl; 25 } 26 cerr << clock() << endl; 27 return 0; 28 }
九、夏目友人帐(一)
经典RMQ问题,ST/线段树都可以。
本来想卡线段树做法,想了一下不卡算了= =。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 //线段树 5 #define lson l,m,p<<1 6 #define rson m+1,r,p<<1|1 7 #define Max(a,b) (a<b?b:a) 8 #define Min(a,b) (a<b?a:b) 9 #define INF 999999999 10 11 int N,M; 12 int MaxP[100000*4+10]; 13 int maxT; 14 void Update(int val,int K,int l,int r,int p){ 15 int m=(l+r)>>1; 16 if(l==r){ 17 MaxP[p]=val; 18 return; 19 } 20 if(K<=m) 21 Update(val,K,lson); 22 else 23 Update(val,K,rson); 24 MaxP[p]=Max(MaxP[p<<1],MaxP[p<<1|1]); 25 } 26 void Query(int L,int R,int l,int r,int p){ 27 int m=(l+r)>>1; 28 if(L<=l&&r<=R){ 29 maxT=Max(maxT,MaxP[p]); 30 return; 31 } 32 if(L<=m) 33 Query(L,R,lson); 34 if(R>=m+1) 35 Query(L,R,rson); 36 } 37 int main(){ 38 freopen("test2.in","r",stdin); 39 freopen("test2.out","w",stdout); 40 int i,val,a,b; 41 scanf("%d %d",&N,&M); 42 for(i=1;i<=N;i++){ 43 scanf("%d",&val); 44 Update(val,i,1,N,1); 45 } 46 for(i=1;i<=M;i++){ 47 scanf("%d %d",&a,&b); 48 maxT=0; 49 Query(a,b,1,N,1); 50 printf("%d\n",maxT); 51 } 52 cerr << clock() << endl; 53 return 0; 54 } 55 56 //ST算法 57 int N,M; 58 int A[500005]; 59 int FMax[500005][27]; 60 61 void Init(){ 62 int i,j; 63 for(i=1;i<=N;i++) 64 FMax[i][0]=A[i]; 65 for(i=1;(1<<i)<=N;i++){ 66 for(j=1;j+(1<<i)-1<=N;j++){ 67 FMax[j][i]=max(FMax[j][i-1],FMax[j+(1<<(i-1))][i-1]); 68 } 69 } 70 } 71 72 int Query(int l,int r){ 73 int k=(int)(log(r-l+1)/log(2)); 74 return max(FMax[l][k],FMax[r-(1<<k)+1][k]); 75 } 76 77 int main(){ 78 freopen("test1.in","r",stdin); 79 freopen("test1.out","w",stdout); 80 int i,a,b; 81 scanf("%d %d",&N,&M); 82 for(i=1;i<=N;i++) 83 scanf("%d",&A[i]); 84 Init(); 85 for(i=1;i<=M;i++){ 86 scanf("%d %d",&a,&b); 87 printf("%d\n",Query(a,b)); 88 } 89 cerr << clock() << endl; 90 return 0; 91 }
十、夏目友人帐(二)
这里就不说怎么推的了,到时候认真听我黑板上讲23333。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 const int N = 210; 6 const int Q = 1010; 7 int f[Q][N][N]; 8 int p[Q]; 9 int c[N][N]; 10 11 int main(){ 12 freopen("test3.in","r",stdin); 13 freopen("test3.out","w",stdout); 14 ios_base::sync_with_stdio(false); 15 cin.tie(0); 16 cout.tie(0); 17 int n,q;cin>>n>>q; 18 for(int i = 1; i <= n; i++){ 19 for(int j = 1; j <= n; j++){ 20 cin>>c[i][j]; 21 } 22 } 23 for(int i = 1; i <= q; i++){ 24 cin>>p[i]; 25 } 26 memset(f,0x3f,sizeof(f)); 27 int INF = f[0][0][0]; 28 p[0] = 3; 29 f[0][1][2] = 0; 30 for(int i = 1; i <= q; i++){ 31 for(int x = 1; x <= n; x++){ 32 for(int y = 1; y <= n; y++){ 33 if(x != p[i] && y != p[i]) 34 f[i][x][y] = min(f[i][x][y],f[i-1][x][y]+c[p[i-1]][p[i]]); 35 if(p[i] != y && p[i] != p[i-1]) 36 f[i][p[i-1]][y] = min(f[i][p[i-1]][y],f[i-1][x][y]+c[x][p[i]]); 37 if(p[i] != x && p[i] != p[i-1]) 38 f[i][x][p[i-1]] = min(f[i][x][p[i-1]],f[i-1][x][y]+c[y][p[i]]); 39 } 40 } 41 } 42 int ans = INF; 43 for(int i = 1; i<= n; i++){ 44 for(int j = 1; j<= n; j++){ 45 ans = min(ans,f[q][i][j]); 46 } 47 } 48 cout << ans << endl; 49 cerr << clock() << endl; 50 return 0; 51 }
P.S. 其实很多题目都可以卡你们算法,不卡不卡,怕被打= =,后面给你们出卡常数233333
转载于:https://www.cnblogs.com/xenny/p/9971264.html
第二场周赛(递归递推个人Rank赛)——题解相关推荐
- 【考试题解】 递归递推
T1:station 题目描述: 小 VHOS 带着 N 颗山楂球来到 A 班的阵地准备缩到位置上吃山楂球. 但是 A 班大佬们太强了,所以小 VHOS 每经过一个 A 班大佬身边, 他都需要交出他 ...
- 青少年软件编程(202209)(C语言)(枚举递归递推)等级考试(三级)试题及参考答案
等级标准 掌握算法以及算法性能.算法效率的概念: 掌握基本算法中枚举的概念: 掌握基本算法中递归的概念: 掌握自调用函数的应用,实现基本算法中的递归方法: 掌握基本算法中由递归变递推的方法: 能够使用 ...
- codeforce 227D Naughty Stone Piles (贪心+递归+递推)
Description There are n piles of stones of sizes a1, a2, -, an lying on the table in front of you. D ...
- 基础算法 —— 递归/递推 —— 汉诺塔问题(Hanoi)
[问题提出] Hanoi塔由n个大小不同的圆盘和三根木柱a,b,c组成.开始时,这n个圆盘由大到小依次套在a柱上,如图所示. 要求把a柱上n个圆盘按下述规则移到c柱上: (1)一次只能移一个圆盘: ...
- 递归--递推之组合数
排列在上一篇中已经写到,是个典型的深搜题,下面是介绍的组合数, 组合的基本定义是, 但是除了用这种传统的方法来求,可以用递归的方式或者是递推的方式来求, 说道递推,只要会递归, 就会递推了.关键的一部 ...
- OJ2755神器的口袋 普通递归+递推+递推滚动数组
代码如下: import java.util.Scanner; //神器的口袋 public class OJ2755 { static int[] weigth; static int[][] re ...
- 数字三角形(递归/递推)C/C++
递归解法 分析: 这是一道经典的动态规划问题,我们还是从最浅显的算法出发,由浅到深慢慢研究.首先最容易想到的是暴力搜索算法.我们先用一个二维数组map来存放上面的数字三角形,于是有: map[1][1 ...
- 递归递推区别分析与例题总结
递归与递推 文章目录 递归与递推 特点 递归(recursive) 递推(iterative) 例题 递推例子 平面分割问题 直线分割平面(基本结论) 线圈分割平面 折线分割平面 偷懒方法 Catal ...
- PTA—— 递归 递推
个人名片: 博主:酒徒ᝰ. 个人简介:沉醉在酒中,借着一股酒劲,去拼搏一个未来. 专栏:PTA习题及解析 介绍:记录了博主在pta学习练题的一些方法与笔记. 目录 前言 1.简介 2.优点 一.题目 ...
最新文章
- Android-支持多屏幕[译文-2]
- sqlmap tamper脚本编写
- vue双向绑定原理源码解析
- 在Eclipse中打开Hadoop工程
- java计算时间跨度_请问如何使用Java计算时间跨度并格式化输出?
- ADO.NET连接数据库
- 自然语言处理-nltk学习(二)
- hash table(全域散列法实现的哈希表)
- 翻译 - EXT JS 5:Controlling an Application with Router
- 计算机硬件系统的安全,维护硬件系统的计算机安全论文
- mysql 三表left join_mysql left join 3表查询问题
- 51ctopython自动化测试工程师课程价格,Python自动化测试开发实战 一门能就业的测试课...
- 【SpringBoot_ANNOTATIONS】组件注册 03 FilterType
- 算法与数据结构(基于C语言)中线性表的快速排序快速查找
- 设计模式-行为性模式(模板方法模式,策略模式,命令模式,责任链模式,观察者模式,中介者模式,迭代器模式)
- 解决尝试连接“ECONNREFUSED - 连接被服务器拒绝”失败的问题
- EasyUI datagrid editor 中用filebox上传图片失败问题
- 论“搜狗”输入法对用户的影响
- android平板刷成windows,安卓系统的平板电脑可以刷成windows系统吗?
- 忘记本地mysql密码_本地MySQL密码忘了,怎么找回?
热门文章
- linux进程管理与调度
- activitimq集群搭建_Spring-activiti
- nvidia cuda工具包更新9.0版本记录
- Linux系统有线网络抓包程序
- html改变占位字符的颜色,使用CSS更改HTML5输入的占位符颜色
- 【java】Java运行时动态生成类几种方式
- 【java】如何在IDEA 中查看 Class文件的汇编
- 【Elasticsearch】基于 Elasticsearch + kibana 实现 IP 地址分布地图可视化
- 【高并发】怎么演示公平锁和非公平锁?
- 【java】Java 最坑爹的 10 大功能点