【2017.10.27】noip赛前集训 | T1 坐标系【矩乘快速幂优化DP】
T1 坐标系
【题目描述】
从前有个平面直角坐标系。 你每次可以向上、向左或向右走,但不能经过重复的点。 求出你从坐标原点出发,走 n 步有多少种不同的方案。 答案对 109 + 7 取模。
【数据范围】
对于 20% 的数据,n≤10; 对于 40% 的数据,n≤100; 对于 60% 的数据,n≤1000; 对于 80% 的数据,n≤106; 对于 100% 的数据,n≤109。
【题解】
虽然学(da)长(lao)们讲了如何推出状态转移方程,但是本蒟蒻还是没有听懂。
于是,让我们打个表:3, 7, 17, 41 ... ...(不是手动打表,先写了个 dfs。当然,dalao也可以手动打表,比如我旁边的wkd学姐)。
于是,我们就发现了一个状态转移方程: f[ i ] = 2 f[i - 1] + f[i - 2]。
然后,你就会发现,裸的DP是只能可以得80分。
可以用矩乘快速幂来优化一下。
初矩阵是 {3, 7}。
因为已经知道了状态转移方程,所以不难推出构造矩阵 { {0, 1}, {1, 2} }。
AC#include <cstdio> #define ll long long const int MOD = 1e9 + 7; struct Matrix { ll a[2][2]; Matrix () { // 注意矩阵要初始化!!!!!! for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) a[i][j] = 0; } } st, fac; Matrix operator * (Matrix x, Matrix y) { Matrix z; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) z.a[i][j] += (x.a[i][k] % MOD) * (y.a[k][j] % MOD) % MOD; return z; } Matrix Fp(Matrix x, ll n) { Matrix re; // for (int i = 0; i <2; i++) { // for (int j = 0; j < 2; j++) // printf("%d ", re.a[i][j]); // printf("\n"); // } // printf("\n"); re.a[0][0] = re.a[1][1] = 1; for ( ; n; n >>= 1, x = x * x) { if (n & 1) re = re * x; } return re; } ll n; int main() { freopen("coordinate.in", "r", stdin); freopen("coordinate.out", "w", stdout); scanf("%lld", &n); st.a[0][0] = 3; st.a[0][1] = 7; fac.a[0][0] = 0; fac.a[0][1] = 1; fac.a[1][0] = 1; fac.a[1][1] = 2; Matrix ans = st * Fp(fac, n - 1); // for (int i = 0; i <2; i++) { // for (int j = 0; j < 2; j++) // printf("%d ", re.a[i][j]); // printf("\n"); // } // printf("\n"); printf("%lld\n", ans.a[0][0] % MOD); // 千万别忘了 % ,因为这个我 WA 了一次。 return 0; }(再说一遍)千万别忘了给矩阵初始化!!!!!还有取模(有点计算,过程中也要%,不然爆LL就GG了 :-()!!!千万别忘了!!!!!


浙公网安备 33010602011771号