1. 程式人生 > >Codeforces 479E Riding in a Lift:前綴和/差分優化dp

Codeforces 479E Riding in a Lift:前綴和/差分優化dp

spa -s ios cin sin lin 做的 codeforce 當前

題目鏈接: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 }

Codeforces 479E Riding in a Lift:前綴和/差分優化dp