Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 4981 | Accepted: 1663 |
Description
"Buy low; buy lower"
Day 1 2 3 4 5 6 7 8 9 10 11 12
Price 68 69 54 64 68 64 70 67 78 62 98 87
Day 2 5 6 10
Price 69 68 64 62
Input
Output
Sample Input
12 68 69 54 64 68 64 70 67 78 62 98 87
Sample Output
4 2
Source
/* (1)首先利用DP + 二分法求最大降序子序列,时间复杂度是nlogn得到以下数组: val[i]:用来存储输入元素 maxSeqLen[i]:表示以第i个元素结尾可以得到的最大降序子序列的长度; maxTailVal[i]:表示当前长度为i的所有最大降序子序列中尾元素的最大值 最后maxTailVal数组的长度maxTailLen即为最大降序子序列的长度 (2)然后利用maxSeqLen来计数,技术时需要考虑重复情况 利用countv[i]表示以第i个元素结尾可以可以得到的长度为maxSeqLen[i]的最大降序子序列的个数 利用maxLenSets[i](是一个List容器)表示maxSeqLen为i的元素的下标集合 加入一个哨兵元素n + 1,设maxSeqLen[n+1]为maxTailLen + 1, val[n + 1] = -1; 那么从1往n+1遍历,每次遍历采取以下策略来计算countv和维护maxLenSets ->维护maxLenSets:假设d = maxSeqLen[i],首先遍历容器maxLenSets[d]的所有元素如果存在一个 元素j使得val[j] = val[i],则删除j元素;最后插入i元素 ->计算countv[i]:遍历maxLenSets[d - 1]中的所有元素j,如果val[j] > val[i],则countv[i] += countv[j] 最后countv[n + 1]即为所求的计数结果,maxLenSets[i]中元素的唯一性确保了最后结果的唯一性. */ #include <iostream> #include <list> #define MAX_N 5005 using namespace std; int maxSeqLen[MAX_N + 1]; int maxTailVal[MAX_N + 1], maxTailLen; int val[MAX_N + 1], n; list<int> maxLenSets[MAX_N + 1]; int countv[MAX_N + 1]; int main() { int i; scanf("%d", &n); for(i = 1; i <= n; i++) { scanf("%d", &val[i]); //二分DP int l = 1, r = maxTailLen; while(l <= r) { int mid = (l + r) / 2; if(maxTailVal[mid] <= val[i]) r = mid - 1; else l = mid + 1; } maxTailVal[l] = val[i]; maxSeqLen[i] = l; if(l > maxTailLen) maxTailLen = l; } //第一个元素需要特殊处理 countv[1] = 1; maxLenSets[1].push_back(1); val[n + 1] = -1; maxSeqLen[n + 1] = maxTailLen + 1; //遍历后面的n个元素 for(i = 2; i <= n + 1; i++) { int d = maxSeqLen[i]; list<int>::iterator iter = maxLenSets[d].begin(); //扫描d长度List,代替相同的元素 for(; iter != maxLenSets[d].end(); ++iter) if(val[*iter] == val[i]) { maxLenSets[d].erase(iter); break; } maxLenSets[d].push_back(i); //同样d = 1的元素由于没有前驱,所以需要特殊处理 if(d == 1) { countv[i] = 1; continue; } //计算countv[i] iter = maxLenSets[d - 1].begin(); for(; iter != maxLenSets[d - 1].end(); ++iter) if(val[*iter] > val[i]) countv[i] += countv[*iter]; } printf("%d %d/n", maxTailLen, countv[n + 1]); return 0; }