• LA 4123 (计数 递推) Glenbow Museum


    题意:

    这种所有边都是垂直或水平的多边形,可以用一个字符串来表示,一个270°的内角记作O,一个90°的内角记作R。

    如果多边形内存在一个点,能看到该多边形所有的点,则这个多边形对应的序列是合法的。这里长度不作限制,只要长度适当能满足要求即可。

    现给出序列长度,问有多少种序列符合要求。

    分析:

    书上分析地很清楚,罗列一下要点:

    首先对于一个长度为n的合法序列,R的个数为(n+4)/2,O的个数为(n-4)/2,即R比O多4个

    我们要找的序列满足要求:R比O多4个,没有两个O相邻。

    这里先设计了一个O(n2)递推的状态,很好理解,看下面那个O(n)的递推

    f(i, j, k)表示有i个R,有j对相邻的R,k(k=0表示R,k=1表示O)开头,R结尾的序列个数。

    边界:

    f(1, 0, 0) = 1,对应串R;f(1, 0, 1) = 1,对应串OR

    状态转移方程:

    f(i, j, k) = f(i-1, j, k) + f(i-1, j-1, k),第一个代表在最后面加OR,第二个表示在最后面加R

    答案:

    f((n+4)/2, 3, 0) + f((n+4)/2, 4, 1) + f((n+4)/2, 4, 0)

    第一个表示开头结尾都是R的串,串中有3对相邻的R,因为串是环状的,所以首尾也算一对,共4对R

    第二个是O开头,R结尾的串

    第三个看起来是R开头结尾,而且中间还有4对R,但只要在最后加上一个O就行了,这样不影响R的个数,对数,总之不影响整个状态的表示。

     1 #include <cstdio>
     2 
     3 const int maxn = 1000;
     4 
     5 long long d[maxn + 10][5][2], ans[maxn + 10];
     6 
     7 void Init()
     8 {
     9     d[1][0][1] = d[1][0][0] = 1;
    10     for(int i = 2; i <= maxn; i++)
    11         for(int j = 0; j < 5; j++)
    12             for(int k = 0; k < 2; k++)
    13             {
    14                 d[i][j][k] = d[i-1][j][k];
    15                 if(j) d[i][j][k] += d[i-1][j-1][k];
    16             }
    17 
    18     for(int i = 4; i <= maxn; i+= 2)
    19     {
    20         int R = (i>>1) + 2;
    21         ans[i] = d[R][3][0] + d[R][4][1] + d[R][4][0];
    22     }
    23 }
    24 
    25 int main()
    26 {
    27     Init();
    28     int n, kase = 1;
    29     while(scanf("%d", &n) == 1 && n) printf("Case %d: %lld
    ", kase++, ans[n]);
    30 }
    代码君
  • 相关阅读:
    RecyclerView与各种异步图片加载框架不兼容的问题
    课内上机实验3——括号匹配(栈)
    课内上机实验3——删除重复元素
    课内上机实验3——数组内移动0元素至末尾
    课内上机实验3——M集合问题(队列)
    递归实践1——Cnm组合数计算
    【转】Quine的编写
    【转】fork函数详解
    【转】Makefile详解
    VC++6.0程序安装
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4319369.html
Copyright © 2020-2023  润新知