2656: [Zjoi2012]数列(sequence)

本文详细解析了[Zjoi2012]数列(sequence)问题,介绍了利用递归方法求解特定数列通项公式的算法实现,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2656: [Zjoi2012]数列(sequence)

Time Limit: 2 Sec  Memory Limit: 128 MB
Submit: 1351  Solved: 712
[ Submit][ Status][ Discuss]

Description

   小白和小蓝在一起上数学课,下课后老师留了一道作业,求下面这个数列的通项公式:

   小白作为一个数学爱好者,很快就计算出了这个数列的通项公式。于是,小白告诉小蓝自己已经做出来了,但为了防止小蓝抄作业,小白并不想把公式公布出来。于是小白为了向小蓝证明自己的确做出来了此题以达到其炫耀的目的,想出了一个绝妙的方法:即让小蓝说一个正整数N,小白则说出 的值,如果当N很大时小白仍能很快的说出正确答案,这就说明小白的确得到了公式。但这个方法有一个很大的漏洞:小蓝自己不会做,没法验证小白的答案是否正确。作为小蓝的好友,你能帮帮小蓝吗?

Input

      输入文件第一行有且只有一个正整数T,表示测试数据的组数。

     第2~T+1行,每行一个非负整数N。

Output

      输出文件共包含T行。

第i行应包含一个不含多余前缀0的数,它的值应等于An(n为输入数据中第i+1行被读入的整数)

【样例输入】

Sample Input

3

1

3

10

Sample Output

1
2
3


HINT

T<=20,N<=10^100

Source

[ Submit][ Status][ Discuss]

令该数列第i项为ai,要知道ai的值,分两类讨论
i为奇数,,记x = [i/2] y = x + y,ai = ax + ay
i为偶数,,ai = ai/2
考虑递归的做法,,想知道ai,按以上分类递归
但是这样每层扩充点数*2,需要约300~400次
数量难以承受
事实上不需要这么多,每层真正不同的点不超过两个
因为任取两个相邻数按上述讨论,得到的不同数字只有两个
一路压位高精度运算就行了

加法写错。。醉。。c.a[i+1] += c.a[i]%p
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 20;
const int p = 100000000;

struct data{
	int len,a[maxn];
	data(){len = 0; memset(a,0,sizeof(a));}
	data operator + (const data &b)
	{
		data c; int L = max(len,b.len);
		for (int i = 0; i < L; i++)
		{
			c.a[i] += a[i] + b.a[i];
			c.a[i+1] += c.a[i] / p;
			c.a[i] %= p;
		}
		c.len = c.a[L]?L+1:L;
		return c;
	}
	data operator * (const data &b)
	{
		data c; 
		for (int i = 0; i < len; i++)
			for (int j = 0; j < b.len; j++)
			{
				c.a[i+j] += a[i]*b.a[j];
				c.a[i+j+1] += c.a[i+j] / p;
				c.a[i+j] %= p;
			}
		c.len = c.a[len+b.len-1]?len+b.len:len+b.len-1;
		return c;
	}
	data operator / (const int &b)
	{
		data c; int res = 0;
		for (int i = len-1; i >= 0; i--)
		{
			c.a[i] = (a[i] + res*p) / b;
			res = (a[i] + res*p) % b;
		}
		c.len = c.a[len-1]?len:len-1;
		return c;
	}
	bool operator == (const data &b) const
	{
		if (len != b.len) return 0;
		for (int i = len - 1; i >= 0; i--)
			if (a[i] != b.a[i]) return 0;
		return 1;
	}
	bool operator != (const data &b) const
	{
		if (len != b.len) return 1;
		for (int i = len - 1; i >= 0; i--)
			if (a[i] != b.a[i]) return 1;
		return 0;
	}
}X,Y,Z;

int T;
char ch[233];

void Get(data &g)
{
	scanf("%s",ch + 1); 
	int len = strlen(ch + 1),cnt = 0,now = 1,sum;
	for (int i = len; i; i--)
	{
		sum += now*(ch[i]-'0');
		now *= 10; ++cnt;
		if (cnt == 8)
		{
			g.a[g.len++] = sum;
			cnt = sum = 0; now = 1;
		}
	}
	if (cnt) g.a[g.len++] = sum;
}

data Solve(data A,data B,data ta,data tb)
{
	if (A == Y && (B == X || B == Z))
	{
		data ret;
		if (A == Y) ret = ret + ta;
		if (B == Z) ret = ret + tb;
		return ret;
	}
	data NA = X,NB = X,na = X,nb = X,g;
	if (A != X)
	{
		g = A / 2;
		na = na + ta; 
		nb = nb + ta;
		if (g.a[0]&1) NA = g,NB = g + Y;
		else NB = g,NA = g + Y;
	}
	if (B != X)
	{
		g = B / 2;
		if (g.a[0]&1) na = na + tb,NA = g;
		else nb = nb + tb,NB = g;
	}
	return Solve(NA,NB,na,nb);
}

void Print(int x,int res)
{
	if (res == 1) {putchar(x + '0'); return;}
	Print(x/10,res-1);
	putchar(x%10 + '0');
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> T; X.len = 1; 
	Y.a[0] = 1; Y.len = 1;
	Z.a[0] = 2; Z.len = 1;
	while (T--)
	{
		data g,f; Get(g);
		if (g == X) {puts("0"); continue;}
		f = (g.a[0]&1)?Solve(g,X,Y,X):Solve(X,g,X,Y);
		printf("%d",f.a[f.len-1]);
		for (int i = f.len - 2; i >= 0; i--) Print(f.a[i],8);
		puts("");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值