JZOJ3769. 【NOI2015模拟8.14】A+B

本文介绍了一种在斐波拉切数系中进行加法运算的算法,通过利用斐波拉切数的特性,实现了两数相加后的最大化表示。文章详细解释了处理过程中的关键性质,并提供了具体的实现代码。

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

题目大意

对于每个数字x,我们总可以把它表示成一些斐波拉切数字之和。我们可以写成 x = a 1 ∗ F i b 1 + a 2 ∗ F i b 2 + a 3 ∗ F i b 3 + … + a n ∗ F i b n x = a1 * Fib1 + a2 * Fib2 + a3 * Fib3 + … + an * Fibn x=a1Fib1+a2Fib2+a3Fib3++anFibn, 其中 F i b 1 = 1 , F i b 2 = 2 … . F i b [ i ] = F i b [ i – 1 ] + F i b [ I − 2 ] Fib1 = 1, Fib2 = 2…. Fib[i] = Fib[i – 1] + Fib[I - 2] Fib1=1,Fib2=2.Fib[i]=Fib[i1]+Fib[I2], 且 a [ n ] > 0 a[n] > 0 a[n]>0.那么我们称ai为x的一种斐波拉切表示,我们要求最大化 a [ 1 … n ] a[1…n] a[1n],如果 b [ 1 … n ] b[1…n] b[1n] a [ 1 … m ] a[1…m] a[1m]都可以表示 x x x,若 m > n m > n m>n a a a更大,若 m = n m = n m=n,则从高位到低位比,第一个不同处 i i i,若 a i > b i ai > bi ai>bi a a a b b b大。
你的任务很简单,给你两个用斐波拉切数最大化表示的两个数字,输出他们相加后用斐波那契最大化表示的数字。 n < = 1000000 n <= 1000000 n<=1000000

分析

对于这道题很显然你不能将其转化为十进制数再转回去这样肯定时间复杂度过不去。那么分析该如何处理这道题,首先有两个很浅显的性质。

  • a [ i ] a[i] a[i] a [ i + 1 ] a[i + 1] a[i+1]都有值,那么可以将其和转为 a [ i + 2 ] a[i +2] a[i+2]
  • a [ i ] = = 2 a[i] == 2 a[i]==2那么可以将其转化为 a [ i − 2 ] a[i - 2] a[i2] a [ i + 1 ] a[i + 1] a[i+1]

有了以上这两个性质就可以比较流畅地处理出这道题了,直接暴力在外面套一个 w h i l e while while循环,不断用上面两个性质都序列进行更新,当无法再更新时就输出答案,正确性不知道咋整,时间复杂度也是玄学的。还要注意处理一下边界值。

#include <cstdio>
using namespace std;

const int N = 1e6 + 10;
int n,m,a[N],ans[N];
bool flag = 1;

int read()
{
	int x = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
	return x;
}

int min(int a,int b) {return a < b ? a : b;}

int main()
{
	n = read();
	for (int i = 1; i <= n; ++ i) a[i] = read();
	m = read();
	for (int i = 1,u; i <= m; ++ i) u = read(),a[i] += u;
	n = n > m ? n : m;
	while (flag)
	{
		flag = 0;
		for (int i = 2,k; i <= n; ++ i) 
			if (a[i] && a[i - 1]) k = min(a[i],a[i - 1]),a[i + 1] += k,a[i] -= k,a[i - 1] -= k,flag = 1;
		if (a[n + 1]) ++ n;
		for (int i = 2; i <= n; ++ i)
			if (a[i] >= 2) ++ a[i + 1],++ a[i - 2],---- a[i],flag = 1;
		if (a[n + 1]) ++ n;
		a[1] += a[0],a[0] = 0;
		if (a[1] >= 2) a[2] += a[1] / 2,a[1] = a[1] & 1 ? 1 : 0,flag = 1;
	}
	printf("%d ",n);
	for (int i = 1; i <= n; i ++) printf("%d ",a[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值