2020 算法上机赛 C2 - H Paint

题面

Kazamori 得到了一个长度为 \(n\) 的整数序列 \(a_1,a_2,...,a_n\) 。对这 \(n\) 个数中的每一个数,他会选择一种颜色,然后把那个数涂上那种颜色。涂色的要求是:

\[如果 a_i 和 a_j (i<j) 被涂上了同一种颜色,那么 a_i<a_j 。 \]

Kazamori 想知道,如果要满足要求,最少需要多少种颜色。

输入

多组输入数据

每组数据第一行一个整数 \(n\) ,第二行 \(n\) 个用空格隔开的整数 \(a_i\)

输出

对于每组数据,输出一行,一个整数,表示最少需要的颜色种数。

输入样例

5
2 1 4 5 3

输出样例

2

数据范围

\(1≤n≤10^5\)

\(0≤ai≤10^9\)

做法

感兴趣的可以去看一下:最小链覆盖 - Dilworth定理

结论是:正串的最少链覆盖,等于反串的最长链长度。

不过这个题最难的是考场上只允许 C 的提交,需要手写一个 \(O(n\log n)\) 的最长上升子序列

(如果可以用 c++ 的话因该会过不少人吧)

#include<stdio.h>
#include<stdlib.h>

int h[100005], H[100005], dp[100005];
int LIS(int n) 
{
	int ans = 1, l, r, mid;
	for(int i = 1;i <= n; i++){
		l = 1; r = ans;
		mid = (l + r)>>1;
		while(l < r){ 
			if(h[i] < dp[mid]) r = mid; 
			else l = mid+1;
			mid = (l + r) >> 1;
		}
		dp[l] = h[i];
		if(l == ans) ans++; 
	}
	return ans - 1;
}

int n;

void work() {
    for(int i = 1;i <= n; ++i) scanf("%d", &H[i]);
    for(int i = n;i >= 1; --i) h[i] = H[n - i + 1];
    printf("%d\n", LIS(n));
}

int main()
{
    while(scanf("%d", &n) != EOF) 
        work();
	return 0;
}
posted @ 2020-12-31 14:25  Withinlover  阅读(123)  评论(0编辑  收藏  举报