ICPC2021昆明区域赛 L.Simone and graph coloring

  • 题目: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;
}

posted @ 2021-05-21 11:08  ~K2MnO4  阅读(195)  评论(0)    收藏  举报