1. 程式人生 > >LuoGu 1108 低價購買 LIS方案數

LuoGu 1108 低價購買 LIS方案數

std ans 其中 有一個 怎麽 pri clu 轉移 影響

一句話題意:兩個序列的LIS的長度和方案數

首先這裏n方的應該是要比nlog的好的,因為還涉及到一個求方案

主要考慮下第二問, 不同的方案數應該怎麽求

實際上 對於一個長為len的子序列,

它的方案數即為所有長為len-1的,且可以轉移到它的子序列 (都是滿足題意的)的方案數之和

這樣就比較好辦了,直接在原本的求LIS的轉移裏搞搞就行了。

那麽答案就是所有長度為LIS的方案數之和了。

但是還有一個問題,這樣的話根本沒考慮方案是否重復。

那麽怎麽樣把相同的去掉呢??

我們把長度相等,當前對應位上的數也相等的,就先暫定為相等,刪掉其中一個。

因為如果他們之前的也相同, 那麽我們是可以直接全轉移到當前的,刪掉之前的。

如果之前的不相等, 那麽之後它們的後面接上一個不同的數時,再作為兩個判斷就行了,互不影響。

貼下代碼

#include<bits/stdc++.h>
using namespace std;
inline int gi()
{
    int x=0,w=0;char ch=0;
    while(!(ch>=0&&ch<=9))
    {
        if(ch==-) w=1;
        ch=getchar();
    }
    while(ch>=0&&ch<=9)
    x=(x<<3
)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } int n,post[5001],tot[5001],maxn,times[5001]; long long ans; int main() { n=gi(); for(int i=1;i<=n;i++) { post[i]=gi(); tot[i]=1; } for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) if(post[i]<post[j]) tot[i]
=max(tot[i],tot[j]+1); if(tot[i]>maxn) maxn=tot[i]; for(int j=1;j<i;j++) { if(tot[i]==tot[j]&&post[i]==post[j]) times[j]=0; else if(tot[i]==tot[j]+1&&post[i]<post[j]) times[i]+=times[j]; } if(!times[i]) times[i]=1; } for(int i=1;i<=n;i++) if(tot[i]==maxn) ans+=times[i]; printf("%d %d",maxn,ans); return 0; }

LuoGu 1108 低價購買 LIS方案數