qwq一看数据范围就知道这个题的做法
首先我们先考虑一个朴素的dp
我们令
f
[
i
]
[
0
/
1
/
2
]
f[i][0/1/2]
f[i][0/1/2]表示到了第
i
i
i位,有连续
0
,
1
,
2
0,1,2
0,1,2个
A
A
A的方案数。
显然,如果当前位置填
B
B
B。
就相当于当前位置有0连续个A,那么前
i
−
1
i-1
i−1位填
0
,
1
,
2
0,1,2
0,1,2都是合法的
如果当前位置填
A
A
A
那么就相当于当前位置有
1
,
2
1,2
1,2个连续的A,分别能从前
i
−
1
i-1
i−1位有
0
,
1
0,1
0,1个
A
A
A转移过来。
那么转移式子如下 f [ i ] [ 0 ] + = f [ i − 1 ] [ 0 ] + f [ i − 1 ] [ 1 ] + f [ i − 1 ] [ 2 ] f [ i ] [ 1 ] = f [ i − 1 ] [ 0 ] f [ i ] [ 2 ] = f [ i − 1 ] [ 1 ] f[i][0]+=f[i-1][0]+f[i-1][1]+f[i-1][2] \\ f[i][1]=f[i-1][0] \\f[i][2]=f[i-1][1] f[i][0]+=f[i−1][0]+f[i−1][1]+f[i−1][2]f[i][1]=f[i−1][0]f[i][2]=f[i−1][1]
QWQ直接枚举的复杂度是 O ( n ) O(n) O(n)的,无法接受。
我们考虑优化…其实看到 n 能 从 n − 1 n能从n-1 n能从n−1转移,很显然想到矩乘
构造如下矩阵
1 1 0
1 0 1
1 0 0
直接进行矩阵快速幂就好。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 10;
const int mod = 19260817;
struct Ju{
int x,y;
int a[maxn][maxn];
Ju operator* (Ju b)
{
Ju ans;
ans.x=x;
ans.y=b.y;
memset(ans.a,0,sizeof(ans.a));
for (int i=1;i<=ans.x;i++)
for (int j=1;j<=ans.y;j++)
for (int k=1;k<=y;k++)
ans.a[i][j]=(ans.a[i][j]+a[i][k]*b.a[k][j]%mod)%mod;
return ans;
}
};
Ju qsm(Ju i,int j)
{
Ju ans;
ans.x=i.x;
ans.y=i.y;
memset(ans.a,0,sizeof(ans.a));
for (int p=1;p<=i.x;p++) ans.a[p][p]=1;
while (j)
{
if(j&1) ans=ans*i;
i=i*i;
j>>=1;
}
return ans;
}
Ju a;
Ju b;
void init()
{
memset(a.a,0,sizeof(a.a));
a.x=1;
a.y=3;
a.a[1][1]=1;
a.a[1][2]=1;
a.a[1][3]=0;
memset(b.a,0,sizeof(b.a));
b.x=3;
b.y=3;
b.a[1][1]=1;
b.a[1][2]=1;
b.a[2][1]=1;
b.a[2][3]=1;
b.a[3][1]=1;
}
signed main()
{
int m=read();
while (m--)
{
int n=read();
init();
Ju tmp=qsm(b,n-1);
a=a*tmp;
cout<<(a.a[1][1]+a.a[1][2]+a.a[1][3])%mod<<endl;
}
return 0;
}