CF1552E: Colors and Intervals 题解

E:

题意:(妙妙构造)n*k的数列a,n种颜色每种k个。你需要每种颜色选两个位置,并覆盖这两个位置的区间。要求最终所有位置被覆盖的次数不超过 nk1。请你构造方案。


这个 nk1 长的很抽象,没发现什么性质,让人很头痛。我们先想想一般性的思路。

我们一般会贪心选靠前的区间,当覆盖次数超过上限时再寻找下一个区间,但是如果我们按右区间排序,左端会乱跳,不太好统计最大覆盖次数。

我们可以不考虑具体如何覆盖,如果一个区块内我们只选了 nk1 个区间,那么无论这些区间怎么排列都不会超过覆盖上限。那么我们就每选出 nk1 个区间就分一个块。从块儿的右边再选区间。

Solution:

ci,j 为第 i 种颜色第 j 次出现的位置。

我们先把 c1,2, c2,2, c3,2 ... cn,2 排序,取前 nk1 个颜色, ci,2 作为右端点,ci,1 为左端点,把这些颜色的答案确定下来。

接着再把 c1,3, c2,3, c3,3 ... cn,3 排序,在答案还未确定的颜色中选前 nk1 个颜色,ci,3 作为右端点,ci,2 作为左端点,把这些颜色答案确定下来。

你会发现第二次选的 nk1 个区间和第一次选的 nk1 个区间是没有重叠的(第一次选的最后一个颜色的右端点一定小于第二次的任意左端点),相当于分别在两个独立的块儿里。

一直这样排序,你会发现我们一共选了 k1 次,每次确定 nk1 个颜色的答案,所以 k1 次之后所有的颜色答案都确定下来了。

int T; int n,k; int ans[N],a[N]; int lst[N],tim[N],L[N]; struct E{ int r,id; }d[N]; inline bool cmp(E A,E B) { return A.r < B.r; } vector <E> g[N]; int main() { n = read(); k = read(); for(int i=1;i<=n*k;i++) { a[i] = read(); tim[a[i]]++; if(tim[a[i]]>1) g[tim[a[i]]].push_back({i,a[i]}); if(lst[a[i]]) L[i] = lst[a[i]]; lst[a[i]] = i; } int shang = ceil((double)n/(double)(k-1.0)); for(int i=2;i<=k;i++) { sort(g[i].begin(),g[i].end(),cmp); int ci = 0; for(int j=0;j<n;j++) { if(ans[g[i][j].id]) continue; ans[g[i][j].id] = g[i][j].r; ci++; if(ci==shang) break; } } for(int i=1;i<=n;i++) cout<<L[ans[i]]<<" "<<ans[i]<<endl; return 0; }

__EOF__

本文作者枫叶晴
本文链接https://www.cnblogs.com/maple276/p/18030463.html
关于博主:菜菜菜
版权声明:呃呃呃
声援博主:呐呐呐
posted @   maple276  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示