BZOJ 3400 [Usaco2009 Mar]Cow Frisbee Team 奶牛沙盘队:dp【和为f的倍数】
题目链接:http://begin.lydsy.com/JudgeOnline/problem.php?id=1375
题意:
给你n个数,你可以从中选任意多个,但不能不选。问你所选数字之和为f的倍数的方案数。
题解:
表示状态:
dp[i][j] = num of ways
i:考虑到第i个数(还没选)
j:之前所选数之和 MOD f == j
找出答案:
ans = dp[n][0] - 1
不选也是一种方案,但题目种要求不能不选,所以-1。
如何转移:
选或不选第i个数。
dp[i+1][j] += dp[i][j] (不选)
dp[i+1][(j+r[i])%f] += dp[i][j] (选)
边界条件:
dp[0][0] = 1 (什么都不选也是一种方案)
others = 0
AC Code:
1 // state expression: 2 // dp[i][j] = num of ways 3 // i: considering ith cow 4 // j: sum MOD f == j 5 // 6 // find the answer: 7 // dp[n][0] 8 // 9 // transferring: 10 // now: dp[i][j] 11 // dp[i+1][j] += dp[i][j] 12 // dp[i+1][(j+r[i])%f] += dp[i][j] 13 // 14 // boundary: 15 // dp[0][0] = 1 16 // others = 0 17 #include <iostream> 18 #include <stdio.h> 19 #include <string.h> 20 #define MAX_N 2005 21 #define MAX_F 1005 22 #define MOD 100000000 23 24 using namespace std; 25 26 int n,f; 27 int r[MAX_N]; 28 int dp[MAX_N][MAX_F]; 29 30 void read() 31 { 32 cin>>n>>f; 33 for(int i=0;i<n;i++) 34 { 35 cin>>r[i]; 36 } 37 } 38 39 void solve() 40 { 41 memset(dp,0,sizeof(dp)); 42 dp[0][0]=1; 43 for(int i=0;i<n;i++) 44 { 45 for(int j=0;j<f;j++) 46 { 47 dp[i+1][j]=(dp[i+1][j]+dp[i][j])%MOD; 48 dp[i+1][(j+r[i])%f]=(dp[i+1][(j+r[i])%f]+dp[i][j])%MOD; 49 } 50 } 51 } 52 53 void print() 54 { 55 cout<<((dp[n][0]-1)%MOD+MOD)%MOD<<endl; 56 } 57 58 int main() 59 { 60 read(); 61 solve(); 62 print(); 63 }