#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=50;
LL a[N][5];
void initialize()
{
a[1][1]=a[1][2]=a[1][3]=a[1][4]=1;
for(int i=2;i<=45;i++)
{
a[i][1]=a[i-1][2]+a[i-1][3];
a[i][2]=a[i-1][1]+a[i-1][3]+a[i-1][4];
a[i][3]=a[i-1][1]+a[i-1][2]+a[i-1][4];
a[i][4]=a[i-1][2]+a[i-1][3];
}
}
int main()
{
initialize();
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
LL ans=0;
ans=a[n][1]+a[n][2]+a[n][3]+a[n][4];
//printf("%I64d\n",ans);
cout<<ans<<endl;
}
return 0;
}
参考题解:
1.题解1
2.题解2
根据题意,1旁边只能是2/3,2旁边只能是1/3/4,3旁边只能是1/2/4,4旁边只能是2/3,首先看一下数据范围,2或者3的45次方,2^45/3^45,这个超过了2^31,超过了int的数据范围,所以我们需要使用long long
我们使用一个数组来存储数字。第一个位置可以存1/2/3/4,有四种情况,假设第一个位置存的是1/4,那么第二个位置就只能存2/3,只有两种情况,假设第一个位置存的是2/3,第二个位置有三个数字可以选择。那么我们到底应该怎么考虑这个问题?
(笔者也是初学者,所以如有错误欢迎大佬指正)动态规划(dp)来解决这道题, 动态规划最关键的就是建立状态转移方程。
状态转移方程就是这个,
a[1][1]=a[1][2]=a[1][3]=a[1][4]=1;
for(int i=2;i<=45;i++)
{
a[i][1]=a[i-1][2]+a[i-1][3];
a[i][2]=a[i-1][1]+a[i-1][3]+a[i-1][4];
a[i][3]=a[i-1][1]+a[i-1][2]+a[i-1][4];
a[i][4]=a[i-1][2]+a[i-1][3];
}
从第一个元素开始处理,每一次循环,前面的数据是已经被处理过的数据(被计算过),这一点和前缀和的思路有点儿类似。循环结束,所有元素都被处理过了。
输出64位整数,使用%I64d