版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/83662645
题意
有 n 个板子 四种颜色(红绿蓝黄),对 n 个板子涂色,在确保 红绿色板子 均为偶数个的情况下 有多少种涂色方案(对10007取模)
n<1e9
首先 暴力搜索就不用去想了,这道题要是做的话需要 dp 也就是递推的方法 我们试想一下 对于当前 n 块板子一共有几种情况?
An : 红绿都达到偶数个了
Bn : 只有红或绿达到偶数个了
Cn : 都没有达到偶数个
既然DP的思想是由一种已知情况推测出未知情况, 那么 对 An+1 Bn+1 Cn+1 我们都可以用已知的信息推测出。
Ai+1 = 2 * Ai (接下来一块不涂红绿 涂蓝或黄 两种情况) + Bi (那种颜色不满足 涂哪种颜色)
Bi+1 = 2 * Ai(随意涂一个红或绿) + 2 * Bi(随意涂一个蓝或黄) + 2 * Ci(涂红或绿)
Ci+1 = Bi(把凑够偶数个那个颜色涂掉) + 2 * Ci(涂蓝或黄)
这样就凑出了三个递推式
我们似乎发现了一些规律 回想一下之前见到的那个斐波那契数列题,这道题也可以利用矩阵的性质来快速完成掉
纵向还是 [Ai Bi Ci] 而我们需要一个 3*3矩阵, 那么看一下递推式 我们不难推出这个矩阵
[ 2 1 0 ]
X = [ 2 2 2 ] 然后运用快速幂 就可以快速求解 得出的结果 我们就记录在了 第一列 而 第一列第一行 是 Ai
[ 0 1 2 ]
AC代码如下:(这次我尝试了重载运算符)
#include<iostream>
#include<cstring>
using namespace std;
const int mod = 1e4+7;
struct matrix
{
int m[3][3];
matrix friend operator * (matrix a,matrix b)
{
matrix tp;
memset(tp.m,0,sizeof(tp.m));
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
{
if(!a.m[i][j])
{
continue;
}
for(int k=0;k<3;++k)
{
tp.m[i][k]+=(a.m[i][j]*b.m[j][k])%mod;
tp.m[i][k]%=mod;
}
}
}
return tp;
}
};
matrix base;
int pow(matrix x,int n)
{
matrix ans={0};
for(int i=0;i<3;++i)
{
ans.m[i][i]=1;
}
while(n)
{
if(n&1)
ans = ans * x;
x = x * x;
n>>=1;
}
return ans.m[0][0];
}
int n;
int main()
{
int test;
cin>>test;
while(test--)
{
cin>>n;
matrix base={2,1,0,2,2,2,0,1,2};
cout<<pow(base,n)<<endl;
}
return 0;
}