这是本人写的第一次博客,学了半年的基础C语言,初学算法,若有错误还请指正。

E. Tetrahedron

                                                                          time limit per test2 seconds
                                                                     memory limit per test256 megabytes
                                                                                inputstandard input
                                                                              outputstandard output
 You are given a tetrahedron. Let's mark its vertices with letters A, B, C and D correspondingly.
                                                                       

An ant is standing in the vertex D of the tetrahedron. The ant is quite active and he wouldn't stay idle. At each moment of time he makes a step from one vertex to another one along some edge of the tetrahedron. The ant just can't stand on one place.

You do not have to do much to solve the problem: your task is to count the number of ways in which the ant can go from the initial vertex D to itself in exactly n steps. In other words, you are asked to find out the number of different cyclic paths with the length of n from vertex D to itself. As the number can be quite large, you should print it modulo 1000000007 (109 + 7).

Input
The first line contains the only integer n (1 ≤ n ≤ 107) — the required length of the cyclic path.

Output
Print the only integer — the required number of ways modulo 1000000007 (109 + 7).

Sample test(s)
input
2
output
3
input
4
output
21
Note
The required paths in the first sample are:

D - A - D
D - B - D
D - C - D

 
 
笔者高中的时候记得在数学试卷上做过类似的题目, 不过当时是求概率的,所以笔者一看到这道题目的时候就是往概率上想,而走n步的情况总可能就是3的n次方,所以只要求出走n步到达D点的概率,用它乘以总可能的情况数并对10的9次方加7取余便是最终的答案,这里设P(A, n)为第n次到A点的概率,所以P(A, n) + P(B, n) + P(C, n) + P(D, n) = 1; 且由于对称性可以知道,P(A, n)  = P(B, n) = P(C, n), 即P(A, n) = 1/3 * (1 - P(D, n))(1),而第n次到达D点,说明第n - 1次在A, B, C 中的其中一点,而又由于对称性可得,P(D, n) = 1/3*(P(A, n - 1) + P(B, n - 1) + P(C, n - 1)) = P(A, n - 1); 与(1)式联立得P(D, n + 1) = 1/3 * (1 - P(D, n)); 利用高中数列知识可以求得;则第n次到达D点的方法数等于总数(3 ^ n)乘以概率,设第n次到达D点的方法数为dp[n], 则有
;这个可以直接用暴力写,也可以用矩阵快速幂写,在这就不贴代码了,不过高中学过数学竞赛的同学可能会觉得这个式子结构()有点眼熟, 3和-1的次数都是等次幂,让人联想到线性递推数列的求解 : 对于数列An = p * An-1 +  q *An-2, 其特征方程为x^2 = px + q, 假设其两根分别为x1, x2,则(x1, x2不相等时)或(x1 = x2时),a,b为常数,可由给出条件获得,所以可以把中的3和-1分别看成x1,x2,由二次方程(设为x^2 + px + q = 0)的韦达定理的p = -(x1 + x2) = -2, q = x1 *x2 = 3;即方程为x^2 - 2x - 3 = 0,而此方程为数列An = 2 * An-1 +  3 *An-2
的特征方程,由此我们可以得到一个递推关系式为dp[n] = 2 * dp[n - 1] + 3 *dp[n - 2];
下面附上代码:
 #include <cstdio>
#include <cstring>
const int N = 1e7 + ;
const int mod = 1e9 + ;
long long dp[N], n;
void init(){
dp[] = ;
dp[] = ;
for(int i = ; i < N; i ++){
dp[i] = * dp[i - ] + * dp[i - ];
dp[i] %= mod;
}
}
int main(){
init();
while(scanf("%d", &n) == )
printf("%d\n", dp[n]);
return ;
}


不过刚开始这点思路非常复杂,所有笔者就去想dp[n] = 2 * dp[n - 1] + 3 *dp[n - 2]的含义

在纠结了好些时辰之后,终于想通了,我们可以第n - 1步到达D点的情况中把最后一步移到其他2个点,再加一步到D点(假如说本来第n - 1步到达D点的情况为A ->D, 那么先让A走到B或C点再走到D点而此时的补数即为n), 而如果还是要走D点那样必须再多走2步才能再次回到D点,即由本来A ->D变成了A->D->X->D。
X可能为A或B或C,即有三种可能的情况,所以也是为什么dp[n - 2]还要乘以3了。
其实我们没有必要开这么大的数列对a, b每次做不同的更新就行了,就是时间会比较费:
 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod = 1e9 + ;
int n;
long long a, b;
int main(){
while(scanf("%d", &n) == ){
if(n < )
printf("0\n");
else if(n == )
printf("3\n");
else{
a = ;
b = ;
for(int i = ; i <= n - ; i ++){
if(i & )
a = ( * a + * b)%mod;
else
b = ( * b + * a)%mod;
}
if(n & )
printf("%I64d\n", a);
else
printf("%I64d\n", b);
}
}
return ;
}

还有一种思路:假设dp[i][j] 表示第i步走到j点(用0表示D点,1,2,3分别表示A,B,C三个点)则有转移方程:
dp[i][j] += dp[i - 1][k] (k, j 不相等),初始化为dp[1][1] = dp[1][2] = dp[1][3] = 1;
 #include <cstdio>
#include <cstring>
typedef long long lld;
const int N = 1e7 + ;
const int mod = 1e9 + ;
int dp[N][], n;
void init(){
dp[][] = ;
dp[][] = ;
dp[][] = ;
for(int i = ; i < N; i ++){
for(int j = ; j < ; j ++){
for(int k = ; k < ; k ++){
if(k == j )
continue;
dp[i][j] += dp[i - ][k];
dp[i][j] %= mod;
}
}
}
}
int main(){
init();
while(scanf("%d", &n) == )
printf("%d\n", dp[n][]);
return ;
}


其实可以从这个递推关系式可以推出dp[n] = 2 * dp[n - 1] + 3 *dp[n - 2]

解:dp[n][0] = dp[n - 1][1] + dp[n - 1][2] + dp[n - 1][3] = 3 * dp[n - 1][1](A,B,C三点具有对称性)
则dp[n - 1][1] = 1/3 * dp[n][0];
       dp[n - 1][1] = 2 * dp[n - 2][1] + dp[n - 2][0];
联立以上两式,则可得dp[n][0] = 2 * dp[n - 1][0] + 3 *dp[n - 2][0];
即为dp[n] = 2 * dp[n - 1] + 3 *dp[n - 2];
 
其实再次观察,便可得出另一个关系式:
dp[n] = 3 * dp[n - 1] - 3(n为奇数时)
3 * dp[n - 1] +3(n为偶数时)
 #include <cstdio>
#include <cstring>
const int N = 1e7 + ;
const int mod = 1e9 + ;
long long dp[N], n;
void init(){
dp[] = ;
dp[] = ;
for(int i = ; i < N; i ++){
if(i & )
dp[i] = * dp[i - ] - ;
else
dp[i] = * dp[i - ] + ;
dp[i] %= mod;
}
}
int main(){
init();
while(scanf("%d", &n) == )
printf("%d\n", dp[n]);
return ;
}

CodeForces 166E -Tetrahedron解题报告的更多相关文章

  1. codeforces 31C Schedule 解题报告

    题目链接:http://codeforces.com/problemset/problem/31/C 题目意思:给出 n 个 lessons 你,每个lesson 有对应的 起始和结束时间.问通过删除 ...

  2. codeforces 499B.Lecture 解题报告

    题目链接:http://codeforces.com/problemset/problem/499/B 题目意思:给出两种语言下 m 个单词表(word1, word2)的一一对应,以及 profes ...

  3. codeforces 495C. Treasure 解题报告

    题目链接:http://codeforces.com/problemset/problem/495/C 题目意思:给出一串只有三种字符( ')','(' 和 '#')组成的字符串,每个位置的这个字符 ...

  4. codeforces 490B.Queue 解题报告

    题目链接:http://codeforces.com/problemset/problem/490/B 题目意思:给出每个人 i 站在他前面的人的编号 ai 和后面的人的编号 bi.注意,排在第一个位 ...

  5. codeforces 489A.SwapSort 解题报告

    题目链接:http://codeforces.com/problemset/problem/489/A 题目意思:给出一个 n 个无序的序列,问能通过两两交换,需要多少次使得整个序列最终呈现非递减形式 ...

  6. codeforces 485A.Factory 解题报告

    题目链接:http://codeforces.com/problemset/problem/485/A 题目意思:给出 a 和 m,a 表示第一日的details,要求该日结束时要多生产 a mod ...

  7. codeforces 483A. Counterexample 解题报告

    题目链接:http://codeforces.com/problemset/problem/483/A 题目意思:给出一个区间 [l, r],要从中找出a, b, c,需要满足 a, b 互质,b, ...

  8. codeforces 479C Exams 解题报告

    题目链接:http://codeforces.com/problemset/problem/479/C 题目意思:简单来说,就是有个人需要通过 n 门考试,每场考试他可以选择ai, bi 这其中一个时 ...

  9. codeforces 479B Towers 解题报告

    题目链接:http://codeforces.com/problemset/problem/479/B 题目意思:有 n 座塔,第 i 座塔有 ai 个cubes在上面.规定每一次操作是从最多 cub ...

随机推荐

  1. 大数据公益课堂成就你高薪之梦,30W,50W,100W...

    从之前的知道“大数据”这词,到2013年正式开始了解大数据领域,再到2014年深入研究大数据相关的领域,到现在逐渐影响周围的同学.朋友和家人.大数据技术将给我们带来的远不止我们想到的这些.曾经我身边的 ...

  2. 怎么通过 Microsof Office Project 2010 来写功能开发计划

    新建一个Microsof Office Project 2010 功能, 直接填写,可以通过快捷键来改变目录分级情况.(shift+alt+ —> 或者 <—) 也可以通过导航栏上面的摘要 ...

  3. 【转】LINUX 5 常用ftp telnet配置

    LINUX 5 常用ftp telnet配置 一.解决远程登陆乱码问题 目标:在xwindow和其console中使用中文界面,在纯console中使用英文 在/etc/profile最后加上一行 e ...

  4. 令人哭笑不得的org.hibernate.MappingException: Unknown entity

    今天处理的任务是从一套系统中分离出微信易信功能代码添加到另一套系统中..本来是一个很简单的任务,但是分离移植过去后,一运行报了个错: nested exception is org.hibernate ...

  5. Hadoop 分布式文件系统 - HDFS

    当数据集超过一个单独的物理计算机的存储能力时,便有必要将它分不到多个独立的计算机上.管理着跨计算机网络存储的文件系统称为分布式文件系统.Hadoop 的分布式文件系统称为 HDFS,它 是为 以流式数 ...

  6. 【Ext.Net学习笔记】02:Ext.Net用法概览、Ext.Net MessageBus用法、Ext.Net布局

    Ext.Net用法概览 Ext.Net还是很强大,如果运用熟练可以极大的提高编程效率.如果你也要学习Ext.Net,原文博主推荐书籍:<Ext.Net Web 应用程序开发教程>,是英文的 ...

  7. 边工作边刷题:70天一遍leetcode: day 84-2

    要点:这题是combination的应用,从左向右想比从右向左容易. 因为有结果从小到大的要求,暗示用combintion而不是permutation 其实就是从小到大验证因子,每个因子和其对称因子立 ...

  8. bootstrap学习总结-js组件(四)

    这次我们来看下js组件的使用,本篇文章会有点长,希望大家可以耐心看,相信收获会有不少.不少园友加我好友,表示喜欢我写文字的风格,简单明了,这里,再次谢谢你们的支持.一方面,博主自身技术有限,写的东西都 ...

  9. 第23章 SEH结构化异常处理(2)_编译器对系统SEH机制的封装

    23.2 编译器层面对系统SEH机制的封装 23.2.1 扩展的EXCEPTION_REGISTRATION级相关结构:VC_EXCEPTION_REGISTRATION (1)VC_EXCEPTIO ...

  10. Resharper团队协作之TODO

    TODO 需求 首先我想跟大家分享一下我们团队的代码检查流程. 1. 项目经理随时会检查成员的代码,如果发现有不符合规范的代码,会在注释里面加todo.比如,假设leo的代码不符合规范,那么项目经理就 ...