【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_ 点个赞!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值