meaning of the title
Finding strictly ascending subsequence of triples
thinking
Consider violence first
for(int i = 1;i <= n;++i) for(int j = 1;j < i;++j) if(x[i] > x[j] && y[i] > y[j] && z[i] > z[j]) f[i] = max(f[i],f[j] + 1)
Consider using \ (CDQ \) divide and conquer to optimize this \ (dp \).
The general idea is to rank the first dimension first to ensure that the first dimension is strictly ascending. Then \ (CDQ \) a second dimension. The tree array maintains the third dimension (needs to be discretized first). The maximum value of the maintenance prefix of the tree array is used here.
Two \ (bug s \) have been tuned for a long time.
bug1
Directly applied the three-dimensional partial order of the board. In fact, this question can't be like this when \ (CDQ \)
void cdq(int l,int r) { if(r <= l) return; cdq(l,mid),cdq(mid + 1,r); //...... }
Because before \ (cdq \) to the right, you must make sure that the right has obtained the answer from the left. This is the difference between LIS and 3D partial order.
The correct operation should be
void cdq(int l,int r){ if(r <= l) return; cdq(l,mid); //...... cdq(mid + 1,r) }
In fact, this \ (bug \) is quite \ (low \) and I feel that I am mentally retarded 2333
bug2
Because the title says it must be strictly incremental. Therefore, the position of \ (mid \) cannot be taken as the middle directly.
You need to find a different location for \ (x[mid] \) and \ (x[mid + 1] \).
Code
/* * @Author: wxyww * @Date: 2019-02-15 10:45:05 * @Last Modified time: 2019-02-16 15:29:12 */ #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<vector> #include<ctime> using namespace std; typedef long long ll; const int N = 300000 + 10; map<int,int>ma; ll read() { ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x*f; } int ls[N],tree[N]; struct node { int x[10],ans; }a[N]; ll A,P,n; int js; void clear(int pos) { while(pos <= js) { tree[pos] = 0; pos += pos & -pos; } } void update(int pos,int x) { while(pos <= js) { tree[pos] = max(x,tree[pos]); pos += pos & -pos; } } int query(int pos) { int ret = 0; while(pos) { ret = max(ret,tree[pos]); pos -= pos & -pos; } return ret; } node tmp[N]; bool cmp(node x,node y) { if(x.x[1] != y.x[1]) return x.x[1] < y.x[1]; if(x.x[2] != y.x[2]) return x.x[2] < y.x[2]; return x.x[3] < y.x[3]; } bool cmy(node x,node y) { if(x.x[2] != y.x[2]) return x.x[2] < y.x[2]; return x.x[3] < y.x[3]; } void cdq(int l,int r) { if(r <= l) return; //Ensure that the first dimension on the right is strictly larger than that on the left sort(a + l,a + r + 1,cmp); int mid = (l + r) >> 1; int tt = 1e9; for(int i = l;i < r;++i) if(a[i].x[1] != a[i + 1].x[1] && abs(mid - i) < abs(mid - tt)) tt = i; if(tt == 1e9) return; mid = tt; //Ensure the order of the second dimension on both sides cdq(l,mid); sort(a + l,a + mid + 1,cmy); sort(a + mid + 1,a + r + 1,cmy); int L = l,R = mid + 1,now = l; while(L <= mid && R <= r) { if(a[L].x[2] <= a[R].x[2]) { update(a[L].x[3],a[L].ans); ++L; } else a[R].ans = max(a[R].ans,query(a[R].x[3] - 1) + 1),++R; } while(R <= r) a[R].ans = max(a[R].ans,query(a[R].x[3] - 1) + 1),++R; for(int i = l;i <= L;++i) clear(a[i].x[3]); cdq(mid + 1,r); } int main() { A = read(),P = read(),n = read(); ll now = 1; int tot = 0; for(int i = 1;i <= n;++i) for(int j = 1;j <= 3;++j) ls[++tot] = a[i].x[j] = now = now * A % P,a[i].ans = 1; sort(ls + 1,ls + tot + 1); ma[ls[1]] = ++js; for(int i = 2;i <= tot;++i) if(ls[i] != ls[i - 1]) ma[ls[i]] = ++js; for(int i = 1;i <= n;++i) { for(int j = 1;j <= 3;++j) a[i].x[j] = ma[a[i].x[j]]; sort(a[i].x + 1,a[i].x + 4); } cdq(1,n); int ans = 0; for(int i = 1;i <= n;++i) ans = max(ans,a[i].ans); cout<<ans; return 0; }