中南大学OJ 2012年8月月赛,I题,Imagination(题目链接)。
Problem I: Imagination
Description
GBQC国有一个正N边形,各个顶点依次标记为0, 1, …, N-1,小明可以从任意一个顶点开始,每次选择一个未经过的顶点连一条蓝色的线段,然后再以那个点为起点重复以上操作,直到所有的顶点都经过为止。
那么在最终的画线方案中,各条线段之间不交叉的方案有多少种呢?两条线段不交叉意味着两条线段没有公共点或者公共点均为正N边形的顶点。
Figure 1描述了N为3时的所有的合法方案。
Figure 2描述了N为4时的所有的合法方案。
Input
输入包含多组测试数据。
每组数据占一行,包含一个正整数N(3 ≤ N ≤ 1018),含义同上。
Output
对于每组数据用一行输出一个整数,表示在最终的画线方案中,各条线段之间不交叉的方案有多少种。
由于这个数可能很大,所以你只需要输出这个数除以1000000007所得的余数。
Sample Input
3
4
Sample Output
3
8
Hint
由于数据量较大,推荐使用scanf和printf。
解题思路:每次都只向左或右的相邻位置走,否则会把未走过的点划分成两半,导致路线不得不交叉。因此,从某个固定点出发。出最后一条路以外,每个点2个方向,即为 \( \displaystyle\underbrace{2\times2\times\cdots\times2}_{n-2 \, 个\, 2}\) ,即2n-2。一共有n个点,所以乘以n。由于是无向图,因此“A为起点,B为终点”和“B为起点,A为终点”是一样的,所以最终答案要除以2,即为 \( \displaystyle\frac{2^{n-2}\, \cdot \, n}{2} = 2^{n-3} \cdot n \) 。但是n很大,所以要用快速幂来搞。
C++语言源代码如下:
#include <cstdio> #include <cstdlib> using namespace std; const long long MOD_NUM = 1000000007; inline long long power2( long long n ) { long long result = 1; long long partial_result = 2; while( n ) { if ( (n % 2) == 1 ) { result *= partial_result ; result %= MOD_NUM; } partial_result = partial_result * partial_result; partial_result %= MOD_NUM; n /= 2; } return result; } inline long long calc( const long long & n ) { return ( power2( n-3 ) * (n % MOD_NUM) ) % MOD_NUM ; } int main (void) { long long n; while ( scanf( "%lld", &n ) != EOF ) printf( "%lld\n", calc(n) ); return EXIT_SUCCESS; }