格子刷油漆

问题描述

  X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。


  你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
  比如:a d b c e f 就是合格的刷漆顺序。
  c e f d a b 是另一种合适的方案。
  当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
输入格式
  输入数据为一个正整数(不大于1000)
输出格式
  输出数据为一个正整数。
样例输入
2
样例输出
24
样例输入
3
样例输出
96
样例输入
22
样例输出
359635897

Algorithm

fb(n) 从边缘某格开始,到与它相邻的另一个边缘格子结束
fb(n) = fb(n-1) * 2

fa(n) 从某个边缘格子开始的所有情况
fa(n) = fb(n) + 2*fa(n-1) + 4 * fa(n-2)
最后走相邻边缘格 第1步走相邻边缘格 第2步走相邻边缘格

fk(i,n) 一共有n个格子,从中间的第i个格子为起点,任意结束
fk(i,n) = ( fb(i)*fa(n-i)*2 + fb(n-i+1)*fa(i-1)*2 ) * 2
先走左边再右边 先走右边再左边 有两个可能起点

总情况包含:
从某个边缘格开始的所有情况 4 * fa(i)
从中间某个格子开始的所有情况 i从2到n-1求和:fk(i,n)


AC

 1 #include<iostream>
 2 #include<cstring>
 3 
 4 using namespace std;
 5 
 6 typedef long long ll;
 7 
 8 const ll mod = 1e9 + 7;
 9 
10 ll fb[1007], fa[1007];
11 
12 ll fk(int i, int n)
13 {
14     return (fb[i]*fa[n-i]*2%mod + fb[n-i+1]*fa[i-1]*2%mod)*2%mod;
15 }
16 
17 ll f(int n)
18 {
19     if(n == 1) return 2;
20     ll ans = fa[n]*4%mod;
21     for(int i=2;i<n;i++)
22         ans = (ans + fk(i, n))%mod;
23     return ans;
24 }
25 
26 int main()
27 {
28     ll n = 0;
29     cin>>n;
30     memset(fa, 0, sizeof(fa));
31     memset(fb, 0, sizeof(fb));
32     fa[1] = 1;
33     fa[2] = 6;
34     fb[1] = 1;
35     // 预处理 fb 
36     for(int i=2;i<1001;i++)
37         fb[i] = 2*fb[i-1]%mod;
38     for(int i=3;i<1001;i++)
39         fa[i] = (fb[i] + 2*fa[i-1] + 4*fa[i-2])%mod;
40     /*
41     for(int i=1;i<n;i++){
42         cout<<i<<":"<<f(i)<<'\n';
43     }
44     */
45     cout<<f(n)<<'\n';
46     return 0;
47 }
View Code

2019-03-17

20:40:10

posted @ 2019-03-17 20:40  maybeTang  阅读(291)  评论(0编辑  收藏  举报