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 }
  • 相关阅读:
    innodb临键锁锁定范围
    详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)
    解决Jenkins邮件配置问题
    解决import模块后提示无此模块的问题
    【转】Linux下cp: omitting directory `XXX'问题解决
    Python之异常处理(执行python文件时传入参数)
    Python之发邮件
    Python之递归
    Python之参数类型、变量
    linux sed命令详解
  • 原文地址:https://www.cnblogs.com/GXZC/p/2839186.html
Copyright © 2011-2022 走看看