【结论】【出现在所有最长上升子序列中的元素】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必不在一个序列中。
时间限制 : 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(' '); }
相关文章推荐
- 【基础练习】【二分】codevs2188 最长上升子序列(限定元素)题解
- tyvj 1208 最长不下降子序列2 求序列b1,b2,b3,…,bm中所有长度(n)最大上升子序列的个数
- ZOJ 2319 最长上升子序列并输出组成该序列的元素编号
- HDU 1087 Super Jumping! Jumping! Jumping!【最长上升子序列元素总和】
- hdu 1950最长单调上升子序列
- PKU2533 最长上升子序列 DP
- 最长上升子序列LIS算法实现
- pku1887 最长不上升子序列
- 最长上升子序列O(n*lg(n))代码
- zoj 1986 || poj 1631 Bridging Signals(最长上升子序列N*logN)
- 最长上升子序列问题的几种解法
- 最长上升子序列
- 给定一个数组,求数组中所有元素的可能组合(每个元素只出现一次),使其和等于给定数的解决办法
- ZJU2136 Longest Ordered Subsequence - 最长上升子序列nlogn
- HDU1087 最长上升子序列
- pku 1631 Bridging signals nLogn效率的最长上升子序列
- zoj2136 经典动态规划 求最长上升子序列
- 最长上升子序列 变异版 题解
- zoj 1986(最长上升子序列)
- 最长公共上升子序列的另一个O(mn)的算法