51Nod 1376 最长递增子序列的数量 (DP+BIT)
Posted dwtfukgv
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51Nod 1376 最长递增子序列的数量 (DP+BIT)相关的知识,希望对你有一定的参考价值。
题意:略。
析:dp[i] 表示以第 i 个数结尾的LIS的长度和数量,状态方程很好转移,先说长度 dp[i] = max { dp[j] + 1 | a[i] > a[j] && j < i },然后是数量,dp[i] = sigma(dp[j]) if dp[i] == dp[j] + 1。
如果普通转移时间复杂度很高,达不到要求,由于有个求和的操作,可以考虑用BIT优化,先把每个数离散化,然后对每个数只要求小于它的数,并且长度最长的就好了,数量也是,如果长度一样就进行合并,否则不合并,或者更新长度。
代码如下:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <algorithm> #include <vector> #include <map> #include <cctype> #include <cmath> #include <stack> #include <sstream> #include <list> #include <assert.h> #include <bitset> #include <numeric> #define debug() puts("++++") #define gcd(a, b) __gcd(a, b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second #define pb push_back #define sqr(x) ((x)*(x)) #define ms(a,b) memset(a, b, sizeof a) #define sz size() #define pu push_up #define pd push_down #define cl clear() #define all 1,n,1 #define FOR(i,x,n) for(int i = (x); i < (n); ++i) #define freopenr freopen("in.txt", "r", stdin) #define freopenw freopen("out.txt", "w", stdout) using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<LL, int> P; const int INF = 0x3f3f3f3f; const LL LNF = 1e17; const double inf = 1e20; const double PI = acos(-1.0); const double eps = 1e-8; const int maxn = 5e4 + 10; const int maxm = 1e6 + 5; const int mod = 1000000007; const int dr[] = {-1, 0, 1, 0}; const int dc[] = {0, -1, 0, 1}; const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; int n, m; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; inline bool is_in(int r, int c) { return r >= 0 && r < n && c >= 0 && c < m; } void update(P &a, P b){ if(a.fi < b.fi) a = b; else if(a.fi == b.fi){ a.se += b.se; if(a.se >= mod) a.se -= mod; } } P sum[maxn]; inline int lowbit(int x){ return -x&x; } void add(int x, P c){ while(x <= m){ update(sum[x], c); x += lowbit(x); } } P query(int x){ P ans(0, 1); while(x){ update(ans, sum[x]); x -= lowbit(x); } return ans; } int a[maxn]; vector<int> v; int getpos(int x){ return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; } int main(){ scanf("%d", &n); v.resize(n); for(int i = 0; i < n; ++i){ scanf("%d", a+i); v[i] = a[i]; } sort(v.begin(), v.end()); v.resize(unique(v.begin(), v.end()) - v.begin()); m = v.sz; P ans(0, 1); for(int i = 0; i < n; ++i){ int pos = getpos(a[i]); P tmp = query(pos - 1); ++tmp.fi; update(ans, tmp); add(pos, tmp); } printf("%d\n", ans.se); return 0; }
分治:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <algorithm> #include <vector> #include <map> #include <cctype> #include <cmath> #include <stack> #include <sstream> #include <list> #include <assert.h> #include <bitset> #include <numeric> #define debug() puts("++++") #define gcd(a, b) __gcd(a, b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second #define pb push_back #define sqr(x) ((x)*(x)) #define ms(a,b) memset(a, b, sizeof a) #define sz size() #define pu push_up #define pd push_down #define cl clear() #define all 1,n,1 #define FOR(i,x,n) for(int i = (x); i < (n); ++i) #define freopenr freopen("in.txt", "r", stdin) #define freopenw freopen("out.txt", "w", stdout) using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<LL, int> P; const int INF = 0x3f3f3f3f; const LL LNF = 1e17; const double inf = 1e20; const double PI = acos(-1.0); const double eps = 1e-8; const int maxn = 5e4 + 10; const int maxm = 1e6 + 5; const int mod = 1000000007; const int dr[] = {-1, 0, 1, 0}; const int dc[] = {0, -1, 0, 1}; const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; int n, m; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; inline bool is_in(int r, int c) { return r >= 0 && r < n && c >= 0 && c < m; } void update(P &a, P b){ if(a.fi < b.fi) a = b; else if(a.fi == b.fi){ a.se += b.se; if(a.se >= mod) a.se -= mod; } } P dp[maxn], res; int id[maxn], a[maxn]; inline bool cmp(int x, int y){ return a[x] == a[y] ? x > y : a[x] < a[y]; } void dfs(int l, int r){ if(l == r){ update(dp[l], P(1, 1)); return ; } int m = l + r >> 1; dfs(l, m); for(int i = l; i <= r; ++i) id[i] = i; sort(id+l, id+r+1, cmp); P ans = P(0, 0); for(int i = l; i <= r; ++i){ int idx = id[i]; if(idx <= m) update(ans, dp[idx]); else{ P tmp = ans; ++tmp.fi; update(dp[idx], tmp); update(res, tmp); } } dfs(m+1, r); } int main(){ scanf("%d", &n); for(int i = 0; i < n; ++i) scanf("%d", a+i); dfs(0, n-1); printf("%d\n", res.se); return 0; }
以上是关于51Nod 1376 最长递增子序列的数量 (DP+BIT)的主要内容,如果未能解决你的问题,请参考以下文章
51nod 1376 最长递增子序列的数量(不是dp哦,线段树 + 思维)