看見標籤推薦順便就做了吧
記$f[i], g[i]$為$i$的含$i$的字首最長遞增子串行和字尾遞增子串行
只要滿足$f[i] + g[i] == lis + 1$,那麼$i$就是可能的
對於$i$而言,其一定出現在$lis$中時,當且僅當$f[i]$唯一
如果存在$i, j (i < j)$滿足$f[i] = f[j]$,那麼一定有$a[i] > a[j]$,這時這兩者構成的$lis$一定不相同
否則,如果$f[i]$唯一,那麼所有$f$為$f[i] + 1$的點必須由它轉移過來
注:樹狀陣列打快了,結果$i += lowbit(i)$打成了$i ++$.........
#include #include#include
#include
using
namespace
std;
extern inline char
gc()
inline
intread()
while(c >= '
0' && c <= '
9') p = p * 10 + c - '
0', c =gc();
return p *w;
}#define ri register int
#define sid 50050
int n, cnp, h[sid * 2
];int
f[sid], g[sid];
intt[sid], a[sid], v[sid];
inline
int qry(int
x) inline
int mdf(int x, int
v) int
num[sid];
intmain()
sort(h + 1, h + n + n + 1
); cnp = unique(h + 1, h + n + n + 1) - h - 1
;
for(ri i = 1; i <= n; i ++)
a[i] = lower_bound(h + 1, h + cnp + 1, v[i]) -h;
for(ri i = 1; i <= n; i ++)
f[i] = qry(a[i] - 1) + 1
, mdf(a[i], f[i]);
memset(t,
0, sizeof
(t));
for(ri i = 1; i <= n; i ++)
a[i] = lower_bound(h + 1, h + cnp + 1, -v[i]) -h;
for(ri i = n; i >= 1; i --)
g[i] = qry(a[i] - 1) + 1
, mdf(a[i], g[i]);
int ans = 0
;
for(ri i = 1; i <= n; i ++) ans =max(ans, f[i]);
for(ri i = 1; i <= n; i ++)
if(f[i] + g[i] == ans + 1) num[f[i]] ++;
printf("a:
");for(ri i = 1; i <= n; i ++)
if(f[i] + g[i] == ans + 1 && num[f[i]] > 1) printf("
%d "
, i);
printf(
"\nb:");
for(ri i = 1; i <= n; i ++)
if(f[i] + g[i] == ans + 1 && num[f[i]] == 1) printf("
%d "
, i);
return0;
}
51nod1218 最長遞增子串行 V2
喜聞樂見的大水題。先離散化,求一下正的最長上公升子串行,再求一下反的最長下降子串行。然後看這兩個加起來等不等於 lis 1,然後如果能做某個位置的只出現一次,它就是不可替代的。看 吧 include include include include include using namespace st...
51nod 1134 最長遞增子串行
1134 最長遞增子串行 基準時間限制 1秒 空間限制 131072 kb 分值 0給出長度為n的陣列,找出這個陣列的最長遞增子串行。遞增子串行是指,子串行的元素是遞增的 例如 5 1 6 8 2 4 5 10,最長遞增子串行是1 2 4 5 10。input 第1行 1個數n,n為序列的長度 2 ...
51nod 1134 最長遞增子串行
1134 最長遞增子串行 基準時間限制 1 秒 空間限制 131072 kb 分值 0 難度 基礎題 給出長度為n的陣列,找出這個陣列的最長遞增子串行。遞增子串行是指,子串行的元素是遞增的 例如 5 1 6 8 2 4 5 10,最長遞增子串行是1 2 4 5 10。input 第1行 1個數n,n...