Maxim and Increasing Subsequence \operatorname{Maxim\ and\ Increasing\ Subsequence} M a x i m a n d I n c r e a s i n g S u b s e q u e n c e
Title link: luogu CF261D \operatorname{luogu\ CF261D}l u o g u C F 2 6 1 D
Topic translation
Gives you a length of nnn 'sBBB array,AAA meansBBB array copyttArray connected end to end after t times, findAAA longest sequence are risingkkk group querymaxb maxbm a x b meansBBThe largest number in the B array
Sample input
3 3 5 2
3 2 1
1 2 3
2 3 1
Sample output
2
3
3
data range
(Look at the picture below for yourself)
Ideas
This question is a tree-shaped array question.
We can find that if the number of loops exceeds or equals the number of different numbers in the array, the answer is the number of different numbers in the array.
(Choose one for each cycle, from small to large)
Then we look at the situation where the number of loops is less than the number of different numbers in the array. Looking
at the range again, we find that n ∗ maxb <= 2 ∗ 1 0 7 n*maxb<=2*10^7n∗maxb<=2∗107 , then we find that the length of the total sequence must be<= 2 ∗ 1 0 7 <= 2*10^7<=2∗107 .
(Because the number of loops is less than the number of different numbers in the array)
Then you can use dp to find the largest and longest ascending subsequence by using a tree array.
(Because I heard that using line segment trees will TLE)
Code
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int k, n, maxb, t;
int a[100001], sum, ans;
int tree[100001], f[100001];
bool in[100001];
int get(int now) {
//找到当前最长上升子序列
int re = 0;
for (; now; now -= now & (-now))
re = max(re, tree[now]);
return re;
}
void up(int now, int x) {
//修改值
for (; now <= maxb; now += now & (-now))
tree[now] = max(tree[now], x);
}
int main() {
scanf("%d %d %d %d", &k, &n, &maxb, &t);//读入
for (int times = 1; times <= k; times++) {
sum = 0;//初始化
ans = 0;
memset(in, 0, sizeof(in));
memset(tree, 0, sizeof(tree));
memset(f, 0, sizeof(f));
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);//读入
if (!in[a[i]]) {
in[a[i]] = 1;
sum++;//记录有多少个不同的数
}
}
if (sum <= t) {
//循环次数超过数的个数,直接输出数的个数
printf("%d\n", sum);
continue;
}
for (int i = 1; i <= t; i++)//枚举复制了多少次
for (int j = 1; j <= n; j++) {
//枚举到哪一个
int now = get(a[j] - 1) + 1;//求出最长上升子序列
if (now > f[j]) {
//比上一次复制的还要高
f[j] = now;
ans = max(ans, now);
up(a[j], now);//修改
}
}
printf("%d\n", ans);//输出
}
return 0;
}