zoukankan      html  css  js  c++  java
  • Codeforces 479E Riding in a Lift:前缀和/差分优化dp

    题目链接:http://codeforces.com/problemset/problem/479/E

    题意:

      有一栋n层的房子。

      还有一个无聊的人在玩电梯,每次玩电梯都会从某一层坐到另外一层。

      他初始在a层,然后要玩k次电梯。

      这栋楼里还有一个神秘实验室,在b层。

      这让他每次坐电梯受到了限制:

        当前在x层,然后要坐到y层,则必须满足|x-y|<|x-b|

      问你共有多少种坐电梯的方案。

    题解:

      表示状态:

        dp[i][j] = numbers

        表示当前在第i层,已经坐了j次电梯,此时的方案数。

      找出答案:

        ans = ∑ dp[i][k]

      如何转移:

        若当前在第i层,则移动距离最大为r = |i-b|-1

        dp[i-r to i-1][j+1] += dp[i][j]

        dp[i+1 to i+r][j+1] += dp[i][j]

        注意判断越界。

      边界条件:

        set dp = 0

        dp[a][0] = 1

      前缀和/差分优化:

        如果直接去做的话,枚举状态要O(N^2),转移要O(N),总复杂度O(N^3)明显超了。

        所以考虑将转移变成O(1)的。

        因为转移是给一段区间加上同一个值,所以可以用差分去做,转移完之后在求一边前缀和就变成了原值。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 5005
     5 #define MAX_K 5005
     6 #define MOD 1000000007
     7 
     8 using namespace std;
     9 
    10 int n,a,b,k;
    11 int dp[MAX_N][MAX_K];
    12 
    13 inline int abs(int x)
    14 {
    15     return x>0 ? x : -x;
    16 }
    17 
    18 inline int mod(int x)
    19 {
    20     return (x%MOD+MOD)%MOD;
    21 }
    22 
    23 void sec(int x,int y,int v,int id)
    24 {
    25     if(x>y || y<=0 || x>n) return;
    26     x=max(x,1); x=min(x,n);
    27     y=max(y,1); y=min(y,n);
    28     dp[x][id]=mod(dp[x][id]+v);
    29     dp[y+1][id]=mod(dp[y+1][id]-v);
    30 }
    31 
    32 int main()
    33 {
    34     cin>>n>>a>>b>>k;
    35     memset(dp,0,sizeof(dp));
    36     dp[a][0]=1;
    37     for(int j=0;j<k;j++)
    38     {
    39         for(int i=1;i<=n;i++)
    40         {
    41             int r=abs(i-b)-1;
    42             sec(i-r,i-1,dp[i][j],j+1);
    43             sec(i+1,i+r,dp[i][j],j+1);
    44         }
    45         for(int i=1;i<=n;i++)
    46         {
    47             dp[i][j+1]=mod(dp[i][j+1]+dp[i-1][j+1]);
    48         }
    49     }
    50     int ans=0;
    51     for(int i=1;i<=n;i++) ans=mod(ans+dp[i][k]);
    52     cout<<ans<<endl;
    53 }
  • 相关阅读:
    EasyUI限制时间选择(开始时间小于结束时间)
    C# readonly与const的区别
    C# Lambda 表达式
    C# 扩展方法
    C# 枚举enum
    Visual Studio中的“build”、“rebuild”、“clean”的区别
    无root开热点教程
    数据库锁
    安卓:标题栏右上角添加按钮
    安卓:从assets目录下复制文件到指定目录
  • 原文地址:https://www.cnblogs.com/Leohh/p/8245103.html
Copyright © 2011-2022 走看看