2021 ICPC昆明站——L

阅读: 评论:0

2021 ICPC昆明站——L

2021 ICPC昆明站——L

题意:

给出一个长度为 n 的全排列数,对于每个逆序对之间连一条边,构成一个图(可能不连通) n≤1e6。
现要将该图染色,满足任意相邻两点颜色不同。
问最少用多少种颜色?输出染色方案。

T组测试样例,T≤1e6; sum{n} ≤ 1e6。

思路:

如果建边跑的话,最坏情况下光是建边就是 N 2 N^2 N2,所以建边不可行。
最多1e6个测试样例,所以应该是思维题。

对于一个位置 i 上的数 x,其需要和后面比 x 小的数所在位置相连,两个位置上颜色不能相同。
为了使得染色种类最少,而且保证相邻位置不能同一颜色,所以对于一个位置 i,其染色编号为其后面所有相连位置的染色最大编号+1
又因为数列为全排列,所以一个数对应一种颜色,也就是说,一个位置上的数 x,其染色编号为:数 [1,x-1] 中,其染色编号最大值 +1。

可以用线段树或树状数组求 区间最大值。

Code:

const int N = 1000010, mod = 1e9 + 7;
int T, n, m;
struct Node{int l,r;int maxa;
}a[4*N];
int ans[N], b[N], f[N];void build(int u,int l,int r)
{a[u].l=l,a[u].r=r,a[u].maxa=0;if(l==r) return;else{int mid=l+r>>1;build(u<<1,l,mid);build(u<<1|1,mid+1,r);}
}int query(int u,int l,int r)
{if(a[u].l>=l&&a[u].r<=r){return a[u].maxa;}else{int mid=a[u].l+a[u].r>>1;int max1=0,max2=0;if(l<=mid) max1=query(u<<1,l,r);if(r>mid) max2=query(u<<1|1,l,r);return max(max1,max2);}
}void pushup(int u){a[u].maxa=max(a[u<<1].maxa,a[u<<1|1].maxa);
}void modify(int u,int x,int y)
{if(a[u].l==a[u].r){a[u].maxa=y;}else{int mid=a[u].l+a[u].r>>1;if(x<=mid) modify(u<<1,x,y);else modify(u<<1|1,x,y);pushup(u);}
}int main(){Ios;cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++) cin>>b[i], f[i]=0;build(1,1,n);int ans=0;for(int i=n;i>=1;i--){int maxa=query(1,1,b[i]-1)+1;f[b[i]]=maxa;modify(1,b[i],maxa);ans=max(ans,maxa);}cout<<ans<<"n"; //换成endl超时。。for(int i=1;i<=n;i++) cout<<f[b[i]]<<" ";cout<<"n";}return 0;
}

但是好像有LIS的做法?明天看一下。


思路2:LIS。

从后往前求最长上升子序列,记录当前位置在其所在最长上升子序列中的位置。该位置便是该点的染色编号。

朴素做法N^2,二分优化做法NlogN。

观察数列5 3 4 2 ,我们会发现其染色规律:
对于一个数,其染色编号为:其所在的 最后位置到当前位置所构成的最长上升子序列 中的位置。(因为在上升子序列中,一个位置后面的所有位置都是互相连线的,当前位置也要和后面所有位置连线,为了让连线两端颜色不同,该位置的染色编号就要+1;只有这种状态时,才需要新用一种颜色,其他情况不会新增,所以这种方式染色编号最少。)

Code:

typedef pair <int, int> PII;
unordered_map <int, int> mp;const int N = 1000010, mod = 1e9 + 7;
int stk[N];
vector<int> v;
int T, n, m;
int a[N];
int cnt;
int f[N], ans;bool check(int mid,int i)
{if(stk[mid]>=a[i]) return 1;return 0;
}void pd(int i)
{int l=1,r=cnt+1;stk[cnt+1]=1e9;while(l<r){int mid=l+r>>1;if(check(mid,i)) r=mid;else l=mid+1;}if(l==cnt+1) cnt++;stk[l]=a[i];f[a[i]]=l;ans=max(ans,f[a[i]]);
}int main(){Ios;cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++) cin>>a[i],f[i]=0;cnt=0,ans=0;for(int i=n;i>=1;i--){pd(i);}cout<<ans<<"n";for(int i=1;i<=n;i++) cout<<f[a[i]]<<" ";cout<<"n";}return 0;
}

现在看好似不太难,但赛时卡了两个小时。。

本文发布于:2024-01-28 16:19:37,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17064299808682.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:昆明   ICPC
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23