老师开的DP专题 说题目不难 我看了这题 n很大 以前做过很多n很大的 然后是矩阵快速幂加速的DP
DP方程很好推 打了一下草稿 2*2的01矩阵
要是没有m个限制那就是水题了 m最多才10 我想了下 可以分成m+1段矩阵快速幂来求 遇到那几个限制的天数的时候就单独用一个矩阵乘一下
这样的题目做的很少 写了几个小时 最后1A 题目不算难 细心点 矩阵构造很简单 纸上写一下
如果第x天必须是B 矩阵是
0 0 0 0
1 0 1 1
0 0 0 0
0 0 0 0
如果x天没要求
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 1
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod = 1000000007;
struct node
{
int day;
char str[10];
}a[12];
struct Mat
{
long long a[5][5];
};
Mat A, B;
Mat get(Mat x, Mat y)
{
Mat z;
memset(z.a, 0, sizeof(z.a));
for(int i = 1; i <= 4; i++)
for(int j = 1; j <= 4; j++)
for(int k = 1; k <= 4; k++)
{
z.a[i][j] += x.a[i][k]*y.a[k][j];
z.a[i][j] %= mod;
}
return z;
}
void Mat_pow(int n)
{
//puts("s");
if(n <= 0)
return;
while(n)
{
if(n&1)
B = get(A, B);
A = get(A, A);
n >>= 1;
}
}
bool cmp(node a, node b)
{
return a. day < b.day;
}
void init()
{
for(int i = 1; i <= 4; i++)
{
for(int j = 1; j <= 4; j++)
{
if(i == j)
A.a[i][j] = 0;
else
A.a[i][j] = 1;
}
}
}
void init2(int k)
{
memset(A.a, 0, sizeof(A.a));
int p = a[k].str[0] - 'A' + 1;
for(int i = 1; i <= 4; i++)
{
if(i == p)
continue;
A.a[p][i] = 1;
}
}
int main()
{
int n, m;
long long in[5];
while(scanf("%d %d", &n, &m) != EOF)
{
for(int i = 0; i < m; i++)
{
scanf("%d %s", &a[i].day, a[i].str);
}
sort(a, a+m, cmp);
memset(B.a, 0, sizeof(B.a));
for(int i = 1; i <= 4; i++)
B.a[i][i] = 1;
int curr = 1;
in[1] = in[2] = in[3] = in[4] = 1;
init();
for(int i = 0; i < m; i++)
{
init();
int d = a[i].day;
if(d == 1)
{
memset(in, 0, sizeof(in));
in[a[i].str[0]-'A'+1] = 1;
//printf("%d\n", in[1]);
continue;
}
//printf("%d\n", d-curr-1);
Mat_pow(d-curr-1);
curr = d;
init2(i);
B = get(A, B);
}
init();
if(curr < n)
Mat_pow(n-curr);
long long ans = 0;
for(int i = 1; i <= 4; i++)
{
for(int j = 1; j <= 4; j++)
{
ans += B.a[i][j]*in[j];
//printf("%lld %lld ", B.a[i][j], in[j]);
ans %= mod;
}
}
printf("%lld\n", ans);
}
return 0;
}
/*
1 1
1 A
2 1
1 A
1000000000 0
647919529
1000000000 1
1 A
411979884
1000000000 1
100 A
1000000000 2
1 A
100 A
417773600
*/