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

Leohh發表於2017-10-01

題目連結: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 }

 

相關文章