这个题的意思就是求出最长递减子序列的长度以及数量, 第一问很好求, 第二问要求得话会比较麻烦,我们令dp[i]为以i结尾的最长递减子序列的长度,dp1[i]为以i为结尾长度为dp[i]的子序列的个数,因为题意还要求子序列不能重复,现在思考不重复时的情况, 不重复的时候dp1[i]的计算方法是这样的,当dp[i]==1的时候dp1[i]=1, 不等于1的时候自然等于dp1[j]的和, 其中dp[i] = dp[j]+1, a[j]>a[i], 考虑到题意求解不重复的方案数, 因此j转移到i时a[j]不应该有重复,例如5 5 3, 以3结尾的长度为二的子序列个数为1个, 前面两个5里面应该只能选一个,并且应该选后面那个。代码如下:
/* ID: m1500293 LANG: C++ PROG: buylow */ #include <cstdio> #include <algorithm> #include <cstring> #include <set> #include <iostream> #include <vector> using namespace std; typedef long long LL; struct BigInteger { static const int BASE = 100000000; //八位为一基本单位 static const int WIDTH = 8; vector<int> s; BigInteger(long long num=0) { *this = num; } BigInteger operator = (long long num) { s.clear(); do { s.push_back(num%BASE); num /= BASE; }while(num > 0); return *this; } BigInteger operator + (const BigInteger& b) const { BigInteger c; c.s.clear(); for(int i=0, g=0; ;i++) { if(g==0&&i>=s.size() && i>=b.s.size()) break; int x = g; if(i < s.size()) x+=s[i]; if(i < b.s.size()) x += b.s[i]; c.s.push_back(x%BASE); g = x / BASE; } return c; } BigInteger operator += (const BigInteger& b) { *this = *this + b; return *this; } bool operator < (const BigInteger& b) const { if(s.size() != b.s.size()) return s.size() < b.s.size(); for(int i=s.size()-1; i>=0; i--) if(s[i]!=b.s[i]) return s[i]<b.s[i]; return false; } bool operator == (const BigInteger& b) const { return !(b<*this)&&!(*this<b); } void print() { printf("%d", s[s.size()-1]); for(int i=s.size()-2; i>=0; i--) printf("%08d", s[i]); printf("\n"); } }; int n; LL a[5500]; int dp[5500]; //以i为结尾最长下降序列的长度 BigInteger dp1[5500]; int main() { freopen("buylow.in", "r", stdin); freopen("buylow.out", "w", stdout); scanf("%d", &n); for(int i=1; i<=n; i++) cin>>a[i]; dp[1] = 1; dp1[1] = 1; int res1 = 1; set<LL> tp; for(int i=2; i<=n; i++) { tp.clear(); dp[i] = 1; for(int j=1; j<i; j++) if(a[i]<a[j]) dp[i] = max(dp[i], dp[j]+1); res1 = max(res1, dp[i]); if(dp[i]==1) dp1[i] = 1; else { for(int j=i-1; j>=1; j--) //这边注意循环方向 因为可能有a, a, b这种子序列的存在, 查了好久才查出来 if(dp[i]==dp[j]+1 && a[i]<a[j] && tp.find(a[j])==tp.end()) { dp1[i] += dp1[j]; tp.insert(a[j]); } } } BigInteger res2 = 0; tp.clear(); for(int i=n; i>=1; i--) //注意对于相同的数字选择下标最大的那个, 因为下标最大的子序列包括下标较小的子序列。 { if(dp[i]==res1 && tp.find(a[i])==tp.end()) { res2 += dp1[i]; tp.insert(a[i]); } } printf("%d ", res1); res2.print(); return 0; }
时间: 2024-10-13 10:25:29