码迷,mamicode.com
首页 > 其他好文 > 详细

USACO buylow

时间:2016-01-27 23:18:43      阅读:415      评论:0      收藏:0      [点我收藏+]

标签:

  这个题的意思就是求出最长递减子序列的长度以及数量, 第一问很好求, 第二问要求得话会比较麻烦,我们令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;
}

 

USACO buylow

标签:

原文地址:http://www.cnblogs.com/xingxing1024/p/5164704.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!