zoukankan      html  css  js  c++  java
  • 历届试题 格子刷油漆

    问题描述
      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
     
    思路:毕竟是决赛题,难度是很大的(对我来说),看了这位博主的思路,才发现规律真的很奇妙,导航门https://www.jianshu.com/p/214d09476203

    1构造数组a[x]、b[x]。a[x]表示在2 * x的格子条件下,从四个角任意一个角的格子出发,遍历全体格子的方法总数,b[x]表示在2 * x的条件下,从四个角任意一个角的格子出发,遍历全体格子后回到与之相对的格子中的方法总数。
    显然,a[1]=1,b[1]=1。

    递推式:
    a[x]=
    b[x]=b[x-1] * 2
    推导如下:

     
    1. 先考虑出发点在角上,从一个角出发,只有3种可能性。
      (1)先去同一列相邻的格子,然后前往下一列,这就简化成从2 * (x-1)的格子中,从一个角出发,遍历全体格子的 问题。因为前往下一列有两种选法,所以有2 * a[x-1]种方法。
      (2)先去相邻列的同一行的格子。又分为:
      先去左下角,再去右边部分, a[x-2] * 2种方法
      先遍历右边的所有,再回来左下角,b[x-1]种方法
      (3)先去右下角的格子,又分为:
      先去左边格子,再遍历右边,a[x-2] * 2种方法
      先遍历右边,再去左边,b[x-1]种方法
    整理可得
    a[x]=a[x-1] * 2+a[x-2] * 4+b[x-1] * 2
    b[x]=2 * b[x-1]
    而从中间某列的一点(2种选择)出发时,显然不能直接往下走,否则无法遍历所有的点,应当先遍历左边(右边)左右的点,然后回到相对的点,再遍历右边(左边)的点。假设从第i列出发,出发的点有两种选择,第二步也有两种选择,因此所有的走法有2 * (b[i-1] * 2 * 2 * a[n-i]+ 2 * b[n-i] * 2 * a[i-1])种。加法的前一半时先遍历左边,后一半是先遍历右边。

    于是,总数就是4 * a[x]+Σ(2到n-1)2 * (b[i-1] * 2 * 2 * a[n-i]+ 2 * b[n-i] * 2 * a[i-1])

    代码方面注意对取余的处理就行了

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     int x;
     8     cin >> x;
     9     long  long int a[x+1];
    10     long long int b[x+1];
    11     a[1]=1;
    12     b[1]=1;
    13     a[2]=6;
    14     long long int def=1000000007;
    15     for(int i=2;i<=x;i++){
    16         b[i]=(b[i-1]*2);
    17         b[i]%=def;
    18     }
    19     for(int i=3;i<=x;i++){
    20         a[i]=(a[i-1]*2+a[i-2]*4+b[i-1]*2);
    21         a[i]%=def;
    22     }
    23     long long int sum=0;
    24     sum=4*a[x];
    25     for(int i=2;i<=x-1;i++){
    26         sum+=2*(b[i-1]*2*2*a[x-i]%def+2*b[x-i]*2*a[i-1]%def);
    27         sum%=def;
    28     }
    29 if(x==1) sum=2;
    30     cout <<sum;
    31     return 0;
    32 }
  • 相关阅读:
    吐血巨献:VB网络编程(webbrowser+Inet+抓包封包+经验)
    亦思验证码识别系统3.1详解
    开机自动连接宽带程序
    轻松报选修智能报选修程序(适用于正方教学管理系统)
    低调发布一个百度谷歌关键字搜索工具
    解惑:Postmessage函数模拟鼠标单击指定坐标
    分享一些经典资源
    英文单词缩写查询
    css控制的个性导航栏
    导航栏中加入自动弹出下拉菜单
  • 原文地址:https://www.cnblogs.com/henuliulei/p/10494755.html
Copyright © 2011-2022 走看看