daimayuan#884. 最长上升子序列计数 | 线段树优化dp

daimayuan#884. 最长上升子序列计数  | 线段树优化dp

http://oj.daimayuan.top/problem/884

  • f[i] 表示以a[i]结尾的最长上升子序列,cnt[i]表示以a[i]结尾的最长上升子序列的个数。 可以n方转移: f[i] = max(f[j] + 1, f[i]); cnt[i] += cnt[j] | (f[i] == f[j] + 1)
  • 发现f的转移就是在i之前找小于a[i]的最大f[i],这个可以用权值线段树处理
  • 单点修改,区间查询,只需要考虑如何合并
Tr comp( Tr a, Tr b) { if(!a.len) return b; //特判0 if(!b.len) return a; if( a.len == b.len ) return Tr{ a.len, (a.cnt + b.cnt) % mod }; if( a.len > b.len ) return a; return b;}
#include<bits/stdc++.h>using namespace std;#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);//#pragma GCC optimize(3,"Ofast","inline")#define ll long long//#define int long longconst int N = 4e5 + 6;const int M = 2e6 + 6;const ll P = 1e9 + 7;const int INF = 0x3f3f3f3f;const ll LNF = 0x3f3f3f3f3f3f3f3f;const int mod = 1e9 + 7;const double PI = acos(-1.0);struct Tr { ll len, cnt;} tree[N << 2], f[N];Tr comp( Tr a, Tr b) { if(!a.len) return b; if(!b.len) return a; if( a.len == b.len ) return Tr{ a.len, (a.cnt + b.cnt) % mod }; if( a.len > b.len ) return a; return b;}void build( int l, int r, int rt ) { if( l == r ) {   tree[rt] = Tr{0, 1};   return; } int mid = l + r >> 1; build( l, mid , rt << 1 ); build( mid + 1, r, rt << 1 | 1 ); tree[rt] = comp( tree[rt << 1], tree[rt << 1 | 1] );}void modify ( int pos, Tr val, int l, int r, int rt ) { if( l == r ) {   if( tree[rt].len == val.len ) tree[rt].cnt = (tree[rt].cnt + val.cnt) % mod;   else tree[rt] = val;   return; } int mid = l + r >> 1; if( pos <= mid ) modify( pos, val, l, mid, rt << 1 ); else modify( pos, val, mid + 1, r, rt << 1 | 1 ); tree[rt] = comp( tree[rt << 1], tree[rt << 1 | 1] );}Tr query( int a, int b, int l, int r, int rt ) {  if( b < l || a > r) return Tr{0, 1}; if( l >= a && r <= b ) {   return tree[rt]; } int mid = l + r >> 1; return comp( query( a, b, l, mid, rt << 1 ), query( a, b, mid + 1, r, rt << 1 | 1 ) );}int a[N];int main() { IOS int n; cin >> n; vector<int> ve; for ( int i = 1; i <= n; ++ i ) {   cin >> a[i]; ve.push_back(a[i]); } sort(ve.begin(), ve.end()); ve.erase( unique(ve.begin(), ve.end()), ve.end()); for ( int i = 1; i <= n ;++ i ) {   a[i] = lower_bound( ve.begin(), ve.end(), a[i]) - ve.begin() + 1; } int limit = ve.size(); build( 0, limit, 1 ); for ( int i = 1; i <= n; ++ i ) {   f[i] = query( 0, a[i] - 1, 0, limit, 1); f[i].len += 1;   Tr de1 = f[i];   modify( a[i], f[i], 0, limit, 1); } int mx = 1, cnt = 0 ; for ( int i = 1; i <= n; ++ i ) {   if( f[i].len > mx) {     mx = f[i].len, cnt = f[i].cnt;   } else if( f[i].len == mx) {     cnt += f[i].cnt; cnt %= mod;   } } cout << cnt << '\n'; return 0;}
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部