BZOJ 2023 [Usaco2005 Nov]Ant Counting 数蚂蚁:dp【前缀和优化】

题目链接: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 }

 

posted @ 2017-10-01 19:42  Leohh  阅读(345)  评论(0编辑  收藏  举报