老师开的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 */