BZOJ 2023 [Usaco2005 Nov]Ant Counting 數螞蟻:dp【前綴和優化】
阿新 • • 發佈:2017-10-01
答案 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【前綴和優化】