• 「重庆市NOIP模拟赛」独立集


    前言

    知道做法竟然可以 \(\tt \color{red}{WA}\) 3发,真是没谁了。

    题面远长于题解系列。

    题目

    有一天,一个名叫顺旺基的程序员从石头里诞生了。又有一天,他学会了冒泡排序和独立集。在一个图里,独立集就是一个点集,满足任意两个点之间没有边。于是他就想把这两个东西结合在一起。

    众所周知,独立集是需要一个图的。那么顺旺基同学创造了一个算法,从冒泡排序中产生一个无向图。

    这个算法不标准的伪代码如下:

    //输入:点数n,1到n的全排列a 
    //输出:一个点数为n的无向图G
    
    void bubblesortgraph(n,a[]) {
    	创建一个有n个点,0条边的无向图G。
        do { 
            swapped=false
            for i 从 1 到 n-1
                if(a[i]>a[i+1]) { 
                    在G中连接点a[i]和点a[i+1]
                    交换a[i]和a[i+1]
                    swapped =true
                }
        } while(swapped);
        输出图G。
    } //结束。
    

    那么我们要算出这个无向图 G 最大独立集的大小。但是事情不止于此。顺旺基同学有时候心情会不爽,这个时候他就会要求你再回答多一个问题:最大独立集可能不是唯一的,但有些点是一定要选的,问哪些点一定会在最大独立集里。今天恰好他不爽,被他问到的同学就求助于你了。

    a是全排列。

    \(1\le N\le 10^5.\)

    讲解

    数据太大,我们不能把图建出来,所以直接考虑哪些点之间没有边。

    直接可以得到结论是上升子序列,所以第一问的答案就是最长上升子序列的长度。

    第二问直接正反各跑一边即可。

    时间复杂度 \(O(n\log_2n)\)

    代码

    精简
    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 100005;
    int n,ans;
    int a[MAXN],pre[MAXN],suf[MAXN],dp[MAXN],vis[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read();
    	for(int i = 1;i <= n;++ i) a[i] = Read();
    	int cnt = 0;
    	for(int i = 1;i <= n;++ i)
    	{
    		int to = lower_bound(dp+1,dp+cnt+1,a[i])-dp;
    		pre[i] = to; dp[to] = a[i];
    		cnt = Max(cnt,to);
    	}
    	ans = cnt; cnt = 0;
    	for(int i = n;i >= 1;-- i)
    	{
    		a[i] = n-a[i]+1;
    		int to = lower_bound(dp+1,dp+cnt+1,a[i])-dp;
    		suf[i] = to; dp[to] = a[i];
    		cnt = Max(cnt,to);
    	}
    	Put(ans,'\n');
    	for(int i = 1;i <= n;++ i)
    		if(pre[i]+suf[i] > ans) ++vis[pre[i]];
    	for(int i = 1;i <= n;++ i)
    		if(pre[i]+suf[i] > ans && vis[pre[i]] <= 1) Put(i,' ');
    	return 0;
    }
    
  • 相关阅读:
    JS 面向对象
    inline-block元素间隙处理
    MUI
    MUI
    chrome://inspect调试html页面空白,DOM无法加载的解决方案
    MUI
    MUI
    MUI
    MUI
    MUI
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15555106.html
Copyright © 2020-2023  润新知