SRM 501 DIV1 500pt(DP)
给定一个长度为n的序列,每个数值的范围为[-1,40],-1可以替换成0~40之间的数,要求你求出符合以下条件的序列有多少个?
1、每个数都是0~40之间的数
2、对于每一个数A[i],都需要小于等于前面所有数的算术平均值,及 对于 i, 1 <= i < N, 需要满足 A[i] <= (A[0] + A[1] + ... + A[i-1]) / i
3、序列中不存在三个连续的数刚好是严格递减的
题目做法
dp[i][j][k][f]表示当前第i个数和为j,第i-1个数为k,f表示i-2是否小于i-1的符合要求的序列总个数,时间复杂度为O(n^5)
代码:
1 int dp[45][2000][45][2]; 2 class FoxAverageSequence 3 { 4 public: 5 int theCount(vector <int> seq) 6 { 7 memset(dp, 0, sizeof(dp)); 8 int n = seq.size(); 9 if (seq[0] == -1) 10 for (int i = 0; i <= 40; i++) dp[0][i][i][0] = 1; 11 else dp[0][seq[0]][seq[0]][0] = 1; 12 for (int i = 1; i < n; i++) 13 for (int j = 0; j <= 1600; j++) 14 for (int k = 0; k <= 40; k++) 15 for (int f = 0; f < 2; f++) 16 { 17 int num = seq[i]; 18 if (dp[i - 1][j][k][f]) 19 { 20 int tj = j + num, tf = num < k ? 1 : 0; 21 if (num == -1) 22 { 23 for (int a = 0; a <= 40; a++) 24 { 25 tf = a < k ? 1 : 0; 26 tj = j + a; 27 if (f && tf) continue; 28 if (a * i > j) break; 29 dp[i][tj][a][tf] += dp[i - 1][j][k][f]; 30 dp[i][tj][a][tf] %= MOD; 31 32 } 33 34 } 35 else 36 { 37 if (f && tf) continue; 38 if (num * i > j) continue; 39 dp[i][tj][num][tf] += dp[i - 1][j][k][f]; 40 dp[i][tj][num][tf] %= MOD; 41 } 42 } 43 } 44 int ans = 0; 45 for (int i = 0; i <= 1600; i++) 46 for (int j = 0; j <= 40; j++) 47 { 48 ans += dp[n - 1][i][j][0]; 49 ans %= MOD; 50 ans += dp[n - 1][i][j][1]; 51 ans %= MOD; 52 } 53 printf("%d\n",ans); 54 return ans; 55 56 } 57 };