【C++题解】【NOIP2006PJ】数列(sequence)

16 篇文章 0 订阅

题目链接:https://gmoj.net/junior/#main/show/1143

题目描述

给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是:
1,3,4,9,10,12,13,…
(该序列实际上就是:3^0,3^1,3^0+3^1,3^2,3^0+3^2,3^1+3^2,3^0+3^1+3^2,…)
请你求出这个序列的第N项的值(用10进制数表示)。
例如,对于k=3,N=100,正确答案应该是981。

输入

输入文件sequence.in 只有1行,为2个正整数,用一个空格隔开:
k N(k、N的含义与上述的问题描述一致,且3≤k≤15,10≤N≤1000)。

输出

输出文件sequence.out 为计算结果,是一个正整数(在所有的测试数据中,结果均不超过2.1*10^9)。(整数前不要有空格和其他符号)。

样例输入

3 100

样例输出

981

数据范围限制

做法

其实就是一道递推题。

以样例数据为准,如图。


我们设序列为 f f f ,会发现一个规律:

  • f 2 = f 1 ∗ k , f 3 = f 1 ∗ k + 1 f_2=f_1*k,f_3=f_1*k+1 f2=f1k,f3=f1k+1,即 3 = 1 ∗ 3 , 4 = 1 ∗ 3 + 1 3=1*3,4=1*3+1 3=13,4=13+1

  • f 4 = f 2 ∗ k , f 5 = f 2 ∗ k + 1 f_4=f_2*k,f_5=f_2*k+1 f4=f2k,f5=f2k+1,即 9 = 3 ∗ 3 , 10 = 3 ∗ 3 + 1 9=3*3,10=3*3+1 9=33,10=33+1

  • f 6 = f 3 ∗ k , f 7 = f 3 ∗ k + 1 f_6=f_3*k,f_7=f_3*k+1 f6=f3k,f7=f3k+1,即 12 = 4 ∗ 3 , 13 = 4 ∗ 3 + 1 12=4*3,13=4*3+1 12=43,13=43+1

  • f 8 = f 4 ∗ k , f 9 = f 4 ∗ k + 1 f_8=f_4*k,f_9=f_4*k+1 f8=f4k,f9=f4k+1,即 27 = 9 ∗ 3 , 28 = 9 ∗ 3 + 1 27=9*3,28=9*3+1 27=93,28=93+1

  • f 10 = f 5 ∗ k , f 11 = f 5 ∗ k + 1 f_{10}=f_5*k,f_{11}=f_5*k+1 f10=f5k,f11=f5k+1,即 30 = 10 ∗ 3 , 31 = 10 ∗ 3 + 1 30=10*3,31=10*3+1 30=103,31=103+1

  • f 12 = f 6 ∗ k , f 13 = f 6 ∗ k + 1 f_{12}=f_6*k,f_{13}=f_6*k+1 f12=f6k,f13=f6k+1,即 36 = 12 ∗ 3 , 37 = 12 ∗ 3 + 1 36=12*3,37=12*3+1 36=123,37=123+1

我们可以通过模拟直接得出答案:

#include<cstdio>
#define min(a,b) (a<b?a:b)
long long f[1001]={0,1},a=1;
int k,n,l=1;
int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%d%d",&k,&n);
	while(l<=n)
	{
		f[++l]=a*k;
		f[++l]=a*k+1;
		a=f[(l+1)/2];
	}
	printf("%lld",f[n]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

上述代码挺一目了然的,但是我们做这道题的方法的主题是递推,所以我们应该要用递推的方式去做这道题。

通过刚刚我们发现的规律,即可得到的递推式为: f [ i ] = f [ ( ( i − ( i f[i]=f[((i-(i f[i]=f[((i(i% 2 ) ) / 2 ) ] ∗ k + ( i 2))/2)]*k+(i 2))/2)]k+(i% 2 ) 2) 2)

#include<cstdio>
long long f[1005];
int k,n;
int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%d%d",&k,&n);
	for(int i=1;i<=n;i++) f[i]=f[((i-(i%2))/2)]*k+(i%2);
	printf("%lld",f[n]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

当然,我们通过 i i i& 1 = i 1=i 1=i% 2 2 2 可知,递推式也可以改成 f [ i ] = f [ ( ( i − ( i f[i]=f[((i-(i f[i]=f[((i(i& 1 ) ) / 2 ) ] ∗ k + ( i 1))/2)]*k+(i 1))/2)]k+(i& 1 ) 1) 1)

#include<cstdio>
long long f[1005];
int k,n;
int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%d%d",&k,&n);
	for(int i=1;i<=n;i++) f[i]=f[((i-(i&1))/2)]*k+(i&1);
	printf("%lld",f[n]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

写文章不易,望大家给 JG_DF_ 点个赞!

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]:这段代码是一个解决LeetCode上某个题目的C++实现,具体是一个双指针的解法。该题目是计算一个数组中的积水量。代码中使用了两个指针分别指向数组的左右边界,然后通过比较左右指针所指向的元素的大小,来确定当前位置的积水量。具体的计算方法是,如果左指针所指向的元素小于右指针所指向的元素,则对左指针的左边进行操作,如果左指针所指向的元素大于等于右指针所指向的元素,则对右指针的右边进行操作。在每一次操作中,都会更新左边的最大值和右边的最大值,并计算当前位置的积水量。最后返回总的积水量。\[1\] 引用\[2\]:这段代码是另一个解决LeetCode上某个题目的C++实现,具体是一个深度优先搜索的解法。该题目是计算一个二维网格中从起点到终点的可行路径数量。代码中使用了递归的方式进行深度优先搜索,从起点开始,每次向下或向右移动一步,直到到达终点。在每一步移动中,会判断当前位置是否有障碍物,如果有障碍物则返回0,如果到达终点则返回1,否则继续递归搜索下一步的位置。最后返回总的可行路径数量。\[2\] 引用\[3\]:这段代码是另一个解决LeetCode上某个题目的C++实现,具体是一个动态规划的解法。该题目是计算一个数组中的积水量。代码中使用了动态规划的思想,通过遍历数组中的每个元素,分别计算该元素左边和右边的最大值,并计算当前位置的积水量。最后返回总的积水量。\[3\] 综上所述,这三段代码分别是解决LeetCode上不同题目的C++实现,分别使用了双指针、深度优先搜索和动态规划的方法来解决问题。 #### 引用[.reference_title] - *1* *3* [Leetcode 热题100 42.接雨水(C++ 多种解法,错过可惜)](https://blog.csdn.net/qq_51933234/article/details/124637883)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [[C++]Leetcode 不同路径 || 解题思路及详解](https://blog.csdn.net/weixin_62712365/article/details/123951736)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值