- 题目:Simone and graph coloring
- 题意:给出一个序列包含n个点,若满足ai > aj 且i < j则该两点连上一条无向边,最后需要给每个点进行上色,有边相邻的点不能上相同的颜色,问共最少需要多少种颜色,并输出每个结点颜色编号(答案不唯一)(编号为:1 -> 最少需要的颜色数量)
- 题解:求出该序列的最长下降子序列的长度即为答案,可用二分 + 贪心的解法来求解,然后如何编颜色序号在代码中已有注释。
- ps:但此题时间卡的特别死,尽可能用scanf读入与printf输出,然后不要用memset,并且也没必要开一个序列数组进行读入数据。
- 代码:
#include<cstdio>
using namespace std;
const int N = 1e6 + 5;
int t;
int res[N], d[N];
int find_pos(int len, int k)
{
int l = 1, r = len;
while(l < r)
{
int mid = (l + r) / 2;
if(d[mid] <= k) r = mid;
else l = mid + 1;
}
return l;
}
int main()
{
scanf("%d", &t);
while(t --)
{
int n;
scanf("%d", &n);
int len = 0;
for(int i = 1; i <= n; i++)
{
int a;
scanf("%d", &a);
if(d[len] > a || i == 1)
{
d[++len] = a;
res[i] = len; //若a小于d序列中最后一个数,说明可直接放入d序列中,那它必然与d序列中它之前所有的点有边相连,所以编号必须与其他结点不一样
}
else
{
int pos = find_pos(len, a); //找到比当前查询的数字小的第一个数(<= a的上界)
d[pos] = a, res[i] = pos; //此时相当于a把d序列中d[pos]这个结点替换掉,所以可用它的编号进行上色,显然满足条件
}
}
printf("%d\n", len);
for(int i = 1; i <= n; i++) printf("%d ", res[i]);
printf("\n");
}
return 0;
}