poj 2748 Logs Stacking (递推找规律|矩阵乘法)

本文探讨了一个木材堆叠问题,通过递推找出所有可能的木材堆叠形状数量,并给出了一种高效的算法实现方案。

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

Logs Stacking
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 4281 Accepted: 1340

Description

Daxinganling produces a lot of timber. Before loading onto trains, the timberjacks will place the logs to some place in the open air first. Looking from the sideway, the figure of a logs stack is as follows: 

 

We have known that the number of logs in each layer is fewer than the lower layer for at least one log, and that in each layer the logs are connected in a line. In the figure above, there are 12 logs in the bottom layer of the stack. Now, given the number of logs in the bottom layer, the timberjacks want to know how many possible figures there may be. 

Input

The first line of input contains the number of test cases T (1 <= T <= 1000000). Then T lines follow. Every line only contains a number n (1 <= n <= 2000000000) representing the number of logs in the bottom layer.

Output

For each test case in the input, you should output the corresponding number of possible figures. Because the number may be very large, just output the number mod 10^5.

Sample Input

4
1
2
3
5

Sample Output

1
2
5
34

Source

[Submit]   [Go Back]   [Status]   [Discuss]



题解:递推找规律。

f[i]表示底层为i的答案。

f[i]=f[i-1]+f[i-2]*2+f[i-3]*3+...+f[1]*(i-1)+1

可以发现每次是在f[i]的基础上加了sum[i-1]=f[1]+f[2]+...+f[i-1] 

这样就可以O(n)递推。

f[i]=f[i-1]+sum[i-1] 

sum[i]=sum[i-1]+f[i]

发现可以构造矩阵

{f[i-1],sum[i],f[i]}*  { 1 1 0

                         1 2 1

                         0 0 0 } 

可以矩阵乘法依然不可以,所以只能找规律了。

发现f[i]数组是循环的,循环节是75000

其实f[i]=fib[2*i-1] (fib 斐波那契数列 1,1,2,3,5,8,13 ) 找fib的循环节

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 1000003
#define p 100000
#define M 75000 
using namespace std;
int n,m,f[M+3],sum[M+3];
int main()
{
	freopen("a.in","r",stdin);
	freopen("my.out","w",stdout);
	scanf("%d",&n);
	f[0]=1;
	f[1]=1; sum[1]=1;
	for (int i=2;i<=75000;i++)
	 f[i]=(f[i-1]+sum[i-1])%p,sum[i]=(sum[i-1]+f[i])%p;
	for (int i=1;i<=n;i++){
		int x; scanf("%d",&x);
		printf("%d\n",f[x%M]);
	}
}


矩阵乘法的代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 1000003
#define p 100000
using namespace std;
int n,m,f[N],sum[N],num[N];
struct data
{
	int x,pos,ans;
}a[N];
struct vec{
   int a[10][10];
}e,t,ans,ans1;
int cmp(data a,data b)
{
	return a.x<b.x;
}
vec mul(vec a,vec b)
{
	vec c;
	for (int i=1;i<=3;i++)
	 for (int j=1;j<=3;j++)
	  {
	  	c.a[i][j]=0;
	  	for (int k=1;k<=3;k++)
	  	 c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%p)%p;
	  }
	return c;
}
void change(vec &a,vec b)
{
	for (int i=1;i<=3;i++)
	 for (int j=1;j<=3;j++)
	  a.a[i][j]=b.a[i][j];
}
vec quickpow(vec &ans,vec t,int x)
{
	vec base;
	change(base,t);
	while (x)
	{
		if (x&1) ans=mul(ans,base);
		x>>=1;
		base=mul(base,base);
	}
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("my.out","w",stdout);
	/*scanf("%d",&n);
	f[1]=1; sum[1]=1;
	for (int i=2;i<=200000;i++)
	 f[i]=(f[i-1]+sum[i-1])%p,sum[i]=(sum[i-1]+f[i])%p;
	for (int i=1;i<=n;i++){
		int x; scanf("%d",&x);
		printf("%d\n",f[x]);
	}*/
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].pos=i;
    sort(a+1,a+n+1,cmp);
    t.a[1][1]=1; t.a[1][2]=1; t.a[1][3]=0;
    t.a[2][1]=1; t.a[2][2]=2; t.a[2][3]=1;
    t.a[3][1]=0; t.a[3][0]=0; t.a[3][3]=0;
    ans.a[1][1]=0; ans.a[1][2]=1; ans.a[1][3]=0;
    for (int i=1;i<=3;i++) ans1.a[i][i]=1;
    a[0].x=1;
    for (int i=1;i<=n;i++)
    {
        quickpow(ans1,t,a[i].x-a[i-1].x);
        num[a[i].pos]=(ans.a[1][1]*ans1.a[1][2]%p+ans.a[1][2]*ans1.a[2][2]%p)%p;
	}
	for (int i=1;i<=n;i++)
	 printf("%d\n",num[i]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值