zoukankan      html  css  js  c++  java
  • 低价购买(LIS方案统计)

    题意:https://www.luogu.com.cn/problem/P1108

    如果两个数列组成的数字完全相同,那我们说这两个数列相同。

    求出最长下降子序列的方案数。


    题解来自 wjyyy大神。

    dp过程中,f数组存的是最长下降子序列的长度,ff数组的下标i是以i结尾的意思,所以最长下降子序列(除了最后一位外)的数据已经丢失,因此不能在方案数相加时再判断是否能加。

    我们从头来看,

    1. 如果一个数列的第一个数与另一个数列的第一个数相同,那么现在可以判断它们相等,即可以把其中一个删掉(在代码中的处理是t [ j ] =0)。当不同的数接在它的后面时,又可以将它们判断为两个数列,这是不互相影响的。因为两个数列都可以由这个相等的数列转移而来
    2. 如果一个数列的第一个数与另一个数列的第一个数不同,那么它们不等,且无论后面添加什么,都不相等,即不删去,则按照普通的判断继续做。

    由上面的两点,我们已经把重复的删掉,这样可以防止重复计数。

    #include <bits/stdc++.h>
    using namespace std;
    #define max(a,b)    (a>b?a:b)
    int a[5009],f[5009],t[5009];
    //a[i]是题目给的股票价格,f[i]是第i天最长的长度
    //t[i]是以i结尾的方案
    int main()
    {
        int n,maxn=0;
        cin>>n;
        for(int i=1;i<=n;i++)    cin>>a[i],f[i]=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<i;j++)
            {
                if(a[i]<a[j])
                    f[i]=max(f[i],f[j]+1);
            }//目前是正常求最长下降子序列 
            maxn=max(maxn,f[i]);//记下最长的长度 
            for(int j=1;j<i;j++)
            {
                if(f[i]==f[j]&&a[i]==a[j])//一样长而且数列完全一样 
                    t[j]=0;
                else if(f[i]==f[j]+1&&a[i]<a[j])//可以接上前面的
                    t[i]+=t[j]; 
            }
            if(!t[i])    t[i]=1;//为了后面的数转移 
        }    
        int ans=0;
        for(int i=1;i<=n;i++)
            if(f[i]==maxn)    ans+=t[i];
        cout<<maxn<<" "<<ans;
    } 
  • 相关阅读:
    hdu 5387 Clock (模拟)
    CodeForces 300B Coach (并查集)
    hdu 3342 Legal or Not(拓扑排序)
    hdu 3853 LOOPS(概率DP)
    hdu 3076 ssworld VS DDD(概率dp)
    csu 1120 病毒(LICS 最长公共上升子序列)
    csu 1110 RMQ with Shifts (线段树单点更新)
    poj 1458 Common Subsequence(最大公共子序列)
    poj 2456 Aggressive cows (二分)
    HDU 1869 六度分离(floyd)
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12501951.html
Copyright © 2011-2022 走看看