zoukankan      html  css  js  c++  java
  • 【DP】【芝麻开门】

    【题目来源】http://acm.buaa.edu.cn/problem/403/

    【个人体会】觉得自己弱爆了。。。当时做的时候实在不会,问了各路大神,得到的解法也不尽相同,有的至今仍感觉懵懵懂懂。当时看完题目后唯一的想法就是任意的前I个房间都必须有大于I的房间钥匙(除非是N),之后再无进展。。。也曾经想过让DP(I)表示到达不了I这个房间的方案数,当时分为两种情况考虑,一是钥匙编号全部小于I,二是有某些房间钥匙的编号大于I,但是这些房间又是到达不了的。情况二让我感觉很麻烦,于是就退缩不再继续想下去了。现在回头看来,情况二实则可以再进一步,不仅仅是不能到达I,更精确是必然也不能到达I之前的某个房间。

    【题目解析】DP(I)表示的是最远可以到达房间I的方案数,DP(I) = I^I - 最远不能到I的方案数,假设最远能到达房间J, 1<=J<I。那么J+1~I的房间可以随便放钥匙,方案数为I^(I-J)。状态转移方程为DP(I) = I^I - SUM{DP(J) * I ^ (I - J)},只有一个边界条件就是F[1]=1。

          PS:要预先处理出I^J取模的数值,不然会超时。

    【代码如下】

     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 typedef long long int64;
     6 
     7 const int mod = 20121215, Maxn = 101;
     8 int N;
     9 int64 List[Maxn][Maxn], F[Maxn];
    10 
    11 int64 Dp(int i)
    12 {
    13     if (F[i]) return F[i];
    14     if (i == 1) return 1;
    15     int64 sum = List[i][i];
    16     for (int j = 1; j < i; j ++)
    17     {
    18         sum -= ((Dp(j) % mod) * List[i][i - j]) % mod;
    19         if (sum < 0) sum += mod;
    20     }
    21     F[i] = sum;
    22     return sum;
    23 }
    24 
    25 void Prework()
    26 {
    27     for (int i = 1; i < Maxn; i ++)
    28     {
    29         List[i][0] = 1;
    30         for (int j = 1; j < Maxn; j ++)
    31             List[i][j] = ((List[i][j - 1] % mod) * i) % mod;
    32     }
    33 }
    34 
    35 int main()
    36 {
    37     Prework();
    38     while (cin >> N) cout << Dp(N) << endl;
    39     return 0;
    40 }
  • 相关阅读:
    js实现图片轮播(修改版1)
    动态添加内容到滚动区域
    新闻自动滚动
    多媒体对象(Media Object)
    (Py练习)判断能被几个9整除
    (Py练习)输出乘法口诀表
    (Py练习)输入某年某月判断天数
    文件名称批量修改
    续订Jetbrain学生包
    (Py练习)判断101-200之间的素数个数并输出
  • 原文地址:https://www.cnblogs.com/GXZC/p/2839186.html
Copyright © 2011-2022 走看看