usaco 4.3 Buy Low, Buy Lower

http://train.usaco.org/usacoprob2?a=7BaJNgFLmpD&S=buylow

求最长递减子序列以及方案数,注意重复不算,比如 3 2 3 2 1 ,这里取到最长递减子序列算一种(3 2 1)。

思路:

  最长递减子序列的长度可以直接dp: dp[i]=max(dp[j]+1) (j<i&&a[j]<a[i])。

  而方案数,如果不重复的话,在dp的过程中记录下就可以求了,设cnt[i]为以a[i]为结尾的方案数,那么推完dp的值之后再推一次,当dp[j]+1==dp[i](j<i)时,cnt[i]=cnt[j]。

       然而这里要求重复,那么问题就来了,如何判重,避开重复。

          思路是这样的:

              对于序列........a[j]......a[i]......,如果a[i]==a[j],那么cnt[j]必然<=cnt[i],而且以a[j]为结尾的最有序列一定是以a[i]为结尾的最优序列的子集。

              知道这一点之后思路就很简单了,计算cnt[i]时,遍历j=1~i,对于某个j,如果存在一个k,使j<k<i且a[k]==a[j],那么就不用把cnt[j]加进来了,这样就可以避免重复了。

  最后一个问题,这里要用高精度,自己写了个重载高精度,感觉还行。

/*
ID: huanrui ke
PROG: buylow
LANG: C++
*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=5010;
const int INF=1e9+10;

int n;
ll a[maxn];
int dp[maxn],Next[maxn];
struct BigNum
{
    int a[110],len;
    void init()
    {
        MS0(a);len=0;
    }
    void eq(ll x)
    {
        init();
        while(x){
            a[++len]=x%10;
            x/=10;
        }
    }
    /*
    friend BigNum operator=(BigNum A,ll x)
    {
        A.init();
        while(x){
            A.a[++len]=x%10;
            x/=10;
        }
        return A;
    }
    */
    friend BigNum operator+(BigNum A,BigNum B)
    {
        BigNum C;C.init();
        C.len=max(A.len,B.len)+1;
        int tag=0;
        REP(i,1,C.len){
            C.a[i]=A.a[i]+B.a[i]+tag;
            tag=C.a[i]/10;
            C.a[i]%=10;
        }
        bool flag=0;
        for(int i=C.len;i>=1;i--){
            if(C.a[i]){
                flag=1;
                C.len=i;break;
            }
        }
        if(!flag) C.len=1;
        return C;
    }
    void Print()
    {
        if(len==0) len=1;
        for(int i=len;i>=1;i--) printf("%d",a[i]);
    }
};BigNum cnt[maxn];

BigNum add(BigNum A,BigNum B)
{
    return A+B;
}

int main()
{
    #define ONLINE_JUDGE
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #else
        freopen("buylow.in","r",stdin);
        freopen("buylow.out","w",stdout);
    #endif
    while(cin>>n){
        REP(i,1,n) scanf("%d",&a[i]);
        a[++n]=0;
        memset(Next,-1,sizeof(Next));
        map<ll,int> mp;
        for(int i=n;i>=1;i--){
            if(mp[a[i]]) Next[i]=mp[a[i]];
            else Next[i]=-1;
            mp[a[i]]=i;
        }
        REP(i,1,n){
            dp[i]=1;
            REP(j,1,i-1){
                if(a[j]>a[i]){
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
        }
        REP(i,1,n) cnt[i].init();
        REP(i,1,n){
            if(dp[i]==1){
                cnt[i].eq(1);
                continue;
            }
            REP(j,1,i-1){
                if(a[j]>a[i]){
                    if(dp[j]+1==dp[i]){
                        if(Next[j]!=-1&&Next[j]<i) continue;
                        cnt[i]=add(cnt[i],cnt[j]);
                    }
                }
            }
        }
        //REP(i,1,n) cout<<dp[i]<<" ";cout<<endl;
        //REP(i,1,n) cout<<cnt[i]<<" ";cout<<endl;
        printf("%d ",dp[n]-1);
        cnt[n].Print();puts("");
    }
    return 0;
}
/**

6
3 3 4 2 2 1
6
3 4 2 3 2 1
1
3
5
3 3 3 2 2
6
4 3 2 5 3 2
*/
View Code
没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/5192131.html