目录
D-Q老师染砖
题目:
衣食无忧的 Q老师 有一天突发奇想,想要去感受一下劳动人民的艰苦生活。
具体工作是这样的,有 N 块砖排成一排染色,每一块砖需要涂上红、蓝、绿、黄这 4 种颜色中的其中 1 种。且当这 N 块砖中红色和绿色的块数均为偶数时,染色效果最佳。
为了使工作效率更高,Q老师 想要知道一共有多少种方案可以使染色效果最佳,你能帮帮他吗?
Input:
第一行为 T,代表数据组数。(1 ≤ T ≤ 100)
接下来 T 行每行包括一个数字 N,代表有 N 块砖。(1 ≤ N ≤ 1e9)
Output:
输出满足条件的方案数,答案模 10007。
Sample Input:
2
1
2
Sample Output:
2
6
题目分析:
- 根据题意,因为是连续格子染色,很明显有子结构的性质,可以考虑 DP 。但是 n 很大,因此考虑矩阵快速幂优化 DP。
- 题目问 n 个格子,红绿均为偶数的染色方案数 ,因此令 A[i] 表示 i 个格子,红绿均为偶数的染色方案数 ,但是只有A[I]不能表示所有的状态,而偶数需要从奇数转移而来,所以添加 B[i] 表示 i 个格子,红绿均为奇数的染色方案数 ,C[i] 表示 i 个格子,红绿有一个为偶数的染色方案数。
- 其A,B,C之间的线性递推公式及由递推式导出的矩阵快速幂等式如下:
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
//a[i]表示i个格子 ,红绿均为偶数
//b[i]表示i个格子 ,红绿均为奇数
//c[i]表示i个格子 ,红绿有一个偶数
const int n=3;
const int p=10007;
struct Matrix
{
int x[n][n];
Matrix operator*(const Matrix& t) const
{
Matrix re;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
re.x[i][j]=0;
for(int k=0;k<n;k++)
{
re.x[i][j]+=x[i][k]*t.x[k][j]%p;
re.x[i][j]%=p;
}
}
}
return re;
}
Matrix(){memset(x,0,sizeof(x));}
Matrix(const Matrix &t){memcpy(x,t.x,sizeof(x));}
};
Matrix quick_pow(Matrix a,int x)
{
Matrix re;
for(int i=0;i<n;i++)
{
re.x[i][i]=1;
}
while(x)
{
if(x&1) re=re*a;
a=a*a;
x>>=1;
}
return re;
}
int main()
{
int t;
cin>>t;
int N;
int ans;
while(t--)
{
cin>>N;
ans=0;
Matrix a;
a.x[0][0]=2;a.x[0][1]=0;a.x[0][2]=1;
a.x[1][0]=0;a.x[1][1]=2;a.x[1][2]=1;
a.x[2][0]=2;a.x[2][1]=2;a.x[2][2]=2;
a=quick_pow(a,N-1);
ans+=(2*a.x[0][0] +0*a.x[0][1]+2*a.x[0][2])%p;
cout<<ans<<endl;
}
return 0;
}
E-Q老师度假
题目:
忙碌了一个学期的 Q老师 决定奖励自己 N 天假期。
假期中不同的穿衣方式会有不同的快乐值。
已知 Q老师 一共有 M 件衬衫,且如果昨天穿的是衬衫 A,今天穿的是衬衫 B,则 Q老师今天可以获得 f[A][B] 快乐值。
在 N 天假期结束后,Q老师最多可以获得多少快乐值?
Input
输入文件包含多组测试样例,每组测试样例格式描述如下:
第一行给出两个整数 N M,分别代表假期长度与 Q老师的衬衫总数。(2 ≤ N ≤ 100000, 1 ≤ M ≤ 100)
接下来 M 行,每行给出 M 个整数,其中第 i 行的第 j 个整数,表示 f[i][j]。(1 ≤ f[i][j] ≤ 1000000)
测试样例组数不会超过 10。
Output
每组测试样例输出一行,表示 Q老师可以获得的最大快乐值。
Sample Input
3 2
0 1
1 0
4 3
1 2 3
1 2 3
1 2 3
Sample Output
2
9
题目分析:
- 根据题意,因为天数连续,很明显有子结构的性质,可以考虑 DP。
- 题目问 n 天后最多快乐值,且每天的快乐值由今日与昨日两天的衣服决定 ,因此令𝑓[i][𝑗]表示第 i 天,穿的衣服为 j 所获得的快乐 值总和。DP 转移方程为:枚举前一天穿的衣服为 k,则 𝑓[𝑖][𝑗]=max(𝑓[𝑖−1][𝑘]+𝐻[𝑘][𝑗]) ,1≤𝑘≤𝑀。
- 但又因为直接求解的复杂度为:𝑂(𝑁∗𝑀∗𝑀)=𝑂(e9),不可行。所以考虑矩阵快速幂优化。
- 其根据DP转移方程式导出的矩阵快速幂等式如下:
与一般的矩阵快速幂的转变与区别如下:
(另 注意数据范围,此处数据范围应为long long)
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
const int maxm=1e2+5;
long long int f[maxm][maxm];//f[i][j]表示第i天,穿的衣服为j所获得的快乐值总和
int N,M;
struct Matrix
{
long long int x[maxm][maxm];
Matrix operator*(const Matrix& t) const
{
Matrix re;
for(int i=0;i<M;i++)
{
for(int j=0;j<M;j++)
{
re.x[i][j]=0;
for(int k=0;k<M;k++)
{
re.x[i][j]=max(re.x[i][j],x[i][k]+t.x[k][j]);
}
}
}
return re;
}
Matrix(){memset(x,0,sizeof(x));}
Matrix(const Matrix &t){memcpy(x,t.x,sizeof(x));}
};
Matrix quick_pow(Matrix a,int x)
{
Matrix re;
int n=M;
for(int i=0;i<M;i++)
{
re.x[i][i]=0;
}
while(x)
{
if(x&1) re=re*a;
a=a*a;
x>>=1;
}
return re;
}
int main()
{
long long int ans;
while(cin>>N>>M)
{
Matrix a;
ans=0;
for(int i=0;i<M;i++)
{
for(int j=0;j<M;j++)
{
cin>>f[i][j];
}
}
for(int i=0;i<M;i++)
{
for(int j=0;j<M;j++)
{
a.x[i][j]=f[j][i];
}
}
a=quick_pow(a,N-1);
for(int i=0;i<M;i++)
{
for(int j=0;j<M;j++)
{
ans=max(ans,a.x[i][j]);
}
}
cout<<ans<<endl;
}
return 0;
}