1. 程式人生 > >BZOJ 2023 [Usaco2005 Nov]Ant Counting 數螞蟻:dp【前綴和優化】

BZOJ 2023 [Usaco2005 Nov]Ant Counting 數螞蟻:dp【前綴和優化】

答案 zoj style online nsf side cal mil www.

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=2023

題意:

  有n個家族,共m只螞蟻(n <= 1000, m <= 100000)。

  每個家族有cnt[i]只螞蟻,並且同一家族中的螞蟻無差別。

  從窩裏爬出來x只螞蟻的方案數為f(x)。

  給定a,b,讓你求 ∑ f(a to b) MOD 1000000。

題解:

  表示狀態:

    dp[i][j] = combinations

    i:第i個家族已經考慮過了

    j:目前出來了j只螞蟻

  找出答案:

    ans = ∑ dp[n][a to b]

  如何轉移:

    dp[i][j] = ∑ dp[i-1][j-k] (0 <= k <= cnt[i], j-k >= 0)

    即:dp[i][j] = ∑ dp[i-1][max(0,j-cnt[i]) to j];

  邊界條件:

    dp[0][0] = 1

    others = 0

  優化:

    (1)裸dp時間復雜度為O(n * m^2) = 10^13,絕對炸了。。。

      所以前綴和優化:求 ∑ dp[i-1][max(0,j-cnt[i]) to j]。

    (2)裸dp空間復雜度為 n*m(Byte) = 95 MB > 64 MB,又炸了咋辦。。。

      滾動數組。因為dp[i][j]只會用到dp[i-1][...]。

AC Code:

 1 // state expression:
 2 // dp[i][j] = combinations
 3 // i: considering ith group
 4 // j: j ants have been outside
 5 //
 6 // find the answer:
 7 // sigma dp[n][a to b]
 8 //
 9 // transferring:
10 // dp[i][j] = sigma dp[i-1][j-k] (0 <= k <= cnt[i], j-k >= 0)
11 // 12 // boundary: 13 // dp[0][0] = 1 14 // others = 0 15 #include <iostream> 16 #include <stdio.h> 17 #include <string.h> 18 #define MAX_N 1005 19 #define MAX_M 100005 20 #define MOD 1000000 21 22 using namespace std; 23 24 int n,m,a,b; 25 int ans=0; 26 int cnt[MAX_N]; 27 int dp[2][MAX_M]; 28 int sum[2][MAX_M]; 29 30 void read() 31 { 32 cin>>n>>m>>a>>b; 33 memset(cnt,0,sizeof(cnt)); 34 int temp; 35 for(int i=0;i<m;i++) 36 { 37 cin>>temp; 38 cnt[temp]++; 39 } 40 } 41 42 int cal_mod(int x) 43 { 44 return (x%MOD+MOD)%MOD; 45 } 46 47 int cal_sum(int k,int x,int y) 48 { 49 if(x==0) return cal_mod(sum[k&1][y]); 50 return cal_mod(sum[k&1][y]-sum[k&1][x-1]); 51 } 52 53 void update_sum(int k,int x) 54 { 55 if(x==0) sum[k&1][x]=cal_mod(dp[k&1][x]); 56 else sum[k&1][x]=cal_mod(sum[k&1][x-1]+dp[k&1][x]); 57 } 58 59 void solve() 60 { 61 memset(dp,0,sizeof(dp)); 62 dp[0][0]=1; 63 for(int i=0;i<=m;i++) 64 { 65 sum[0][i]=1; 66 } 67 for(int i=1;i<=n;i++) 68 { 69 for(int j=0;j<=m;j++) 70 { 71 dp[i&1][j]=cal_sum(i-1,max(0,j-cnt[i]),j); 72 update_sum(i,j); 73 } 74 } 75 for(int i=a;i<=b;i++) 76 { 77 ans=cal_mod(ans+dp[n&1][i]); 78 } 79 } 80 81 void print() 82 { 83 cout<<ans<<endl; 84 } 85 86 int main() 87 { 88 read(); 89 solve(); 90 print(); 91 }

BZOJ 2023 [Usaco2005 Nov]Ant Counting 數螞蟻:dp【前綴和優化】