求lis的時候呢,我想n^2的做法是很簡單的,二分的話除了最長不上公升或最長不下降子串行不好求之外(畢竟要注意細節)於是從中發現了,求lis真正的序列也是十分不好求出的尤其是字典序最大的不上公升序列了,什麼的很難求的,當時好像打了hash,玄學找起點,優先佇列維護。等等,可能不是很好的思路吧。
但是求方案數就不一樣了並不需要一些堆什麼的維護。多開乙個陣列在dp的時候進行維護即可我是這樣想的並不是所有的方案數都是乘法原理,加法原理是乘法原理的分支,不能光想著乘法。
下面給出例題求不同的lis方案數。
這道題呢第一問很簡單的,求乙個最長下降子串行即可而且還不算相同的數字,資料範圍5000 n^2當然也是可以過得。所以關鍵是第二問。
問的是不相同的最長下降子串行有多少種,這個問題讓我感覺難以回答,儘管看完題解後恍然大悟,但是剛碰到的時候還是免不了想起了暴力,乘法原理什麼的。
這裡題解上給出的正解是維護乙個t陣列表示以第i個數子為結尾的最長下降子串行的方案數,儘管它可能不是答案但是對答案的累加做出了極大的貢獻所以需要維護一下。
那麼則有另乙個狀態轉移方程了。f[i]==f[j]&&a[i]==a[j]?t[j]=0:0; f[i]==f[j]+1&&a[i]這樣就維護好了t陣列,所以接下來就完事了,仔細思考上述第乙個狀態轉移。如果當前的數字相等和長度都相等的話那麼,就一定是完全相同的序列那麼前乙個對答案就做不出任何貢獻了,因為答案要的是不相同的方案數。
code:
#include#includeview code#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
inline
long
long
read()
while(ch>='
0'&&ch<='9')
return x*f;
}inline
void put(long
long
x)const
int maxn=5002
;int
n;int
a[maxn],f[maxn];
int ans=0,cnt=0
;int
c[maxn];
intmain()
c[i]==0?c[i]=1:0
; }
put(ans);
for(int i=1;i<=n;i++)if(f[i]==ans)cnt+=c[i];
put(cnt);
return0;
}
顯然演算法的複雜度是n^2的所以,為了追求更完美,好吧我也不是完美主義者,不是很想寫了。那就這樣吧。
關於加權的LIS問題
蒟蒻zigzag正在準備聯賽.這個算是這幾天做的唯一乙個值得寫一寫的題吧。首先lis的n 2暴力dp應該都會寫,就是f i max 1 那麼加權的就吧後面的1換成數的權值就行了,如果優先長度的話加一些判斷就行了。那麼o nlogn 怎麼寫?lis的nlogn應該都會寫,就是記乙個陣列d i 表示長度...
洛谷 P1108 低價購買(LIS,統計方案數)
看第乙個要求,很顯然是求最長下降子串行,和lis幾乎一樣,很簡單,再看第二個問號,求最長下降子串行的方案數?這怎麼求?注意 當二種方案 看起來一樣 時 就是說它們構成的 佇列一樣的時候 這2種方案被認為是相同的。這裡就用到了一種基於dp的dp。我們用a i 存原來的數,f i 存以第i個數結尾的最長...
關於LIS和memset 函式
關於最長上公升子串行問題,有兩種演算法,複雜度 o n 2 和 o nlogn 導航 紫書p274,這一種,dp i x 表示的是以i結尾的數的最長子序列是x,演算法就是從第乙個數開始遍歷,再對前面的數進行遍歷,再根據條件不斷地更新dp i 的值。這個演算法的主要在於內層迴圈浪費時間。memset ...