您的位置:首页 > 其它

【结论】【出现在所有最长上升子序列中的元素】NKOJ3500 独立集

2016-11-10 01:13 190 查看
NKOJ3500 独立集

时间限制 : 20000 MS 空间限制 : 165536 KB

评测说明 : 1s

问题描述

有一天,一个名叫顺旺基的程序员从石头里诞生了。又有一天,他学会了冒泡排序和独

立集。在一个图里,独立集就是一个点集,满足任意两个点之间没有边。于是他就想把这两

个东西结合在一起。众所周知,独立集是需要一个图的。那么顺旺基同学创造了一个算法,

从冒泡排序中产生一个无向图。

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



那么我们要算出这个无向图G最大独立集的大小。但是事情不止于此。顺旺基同学有时

候心情会不爽,这个时候他就会要求你再回答多一个问题:最大独立集可能不是唯一的,但

有些点是一定要选的,问哪些点一定会在最大独立集里。今天恰好他不爽,被他问到的同学

就求助于你了。

输入格式

输入包含两行,第一行为N,第二行为1 到N 的一个全排列。

输出格式

输出包含两行,第一行输出最大独立集的大小,第二行从小到大输出一定在最大独立集

的点的编号。

样例输入

3

3 1 2

样例输出

2

2 3

提示

30%的数据满足 N<=16

60%的数据满足 N<=1,000

100%的数据满足 N<=100,000

来源 bs

预处理f,表示从左到右最长上升子序列。g,表示从右往左最长下降子序列

当f[i]+g[i]==ans+1时i点在序列中,当f[i]==f[j]&&g[i]==g[j]时,i、j必不在一个序列中。

#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
#define END fclose(stdin),fclose(stdout);return 0
const int need=100003;
const int oo=1e9;

int n;
int a[need];
//..................................................
inline void in_(int &d)
{
char t=getchar();
while(t<'0'||t>'9')  t=getchar();
for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';
}
inline void out_(int x)
{
if(x>=10) out_(x/10);
putchar(x%10+'0');
}
//..................................................
int f[need];

struct fy
{
int a,b,val;
} w[need<<3];
#define ls (s<<1)
#define rs ((s<<1)|1)

void build(int s,int l,int r)
{
w[s].a=l,w[s].b=r,w[s].val=0;
if(w[s].a==w[s].b) return ;
build(ls,l,(l+r)>>1),build(rs,(l+r)/2+1,r);
}

int d,k;

void change(int s)
{
int mid=(w[s].a+w[s].b)>>1;
if(w[s].a==d&&w[s].b==d)
{
w[s].val=k;
return ;
}
if(d<=mid) change(ls);
else change(rs);
w[s].val=max(w[ls].val,w[rs].val);
}

int get(int s)
{
if(w[s].a>d) return 0;
if(w[s].b<=d) return w[s].val;
return max(get(ls),get(rs));
}
//..................................................
int c[need];
int g[need];

#define lowbit(x) (x&-x)

void change2(int x,int d)
{
for(;x<=n;x+=lowbit(x)) c[x]=max(d,c[x]);
}

int get2(int x)
{
int ans=0;
for(;x>0;x-=lowbit(x)) ans=max(ans,c[x]);
return ans;
}
//..................................................
int cnt[need];
//..................................................

int main()
{
scanf("%d",&n);

build(1,1,n);
int ans=0;
for(int i=1,tmp;i<=n;i++)
{
in_(a[i]);
d=a[i]-1,tmp=get(1);
f[i]=tmp+1;
d=a[i],k=f[i],change(1);
if(f[i]>ans) ans=f[i];
}

for(int i=n,tmp;i>=1;i--)
{
tmp=get2((n-a[i]+1)-1);
g[i]=tmp+1;
change2(n-a[i]+1,g[i]);
}

for(int i=1;i<=n;i++)
{
f[i]+=g[i];
if(f[i]==ans+1)
{
cnt[g[i]]++;
}
}
cout<<ans<<endl;
for(int i=1;i<=n;i++) if(f[i]==ans+1&&cnt[g[i]]==1) out_(i),putchar(' ');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: