当前位置: 首页 > news >正文

洛谷 P7971 [KSN2021] Colouring Balls 题解

人生第一道蓝交互。

观察数据范围,可以考虑数据点分治,分别解决各个 Subtask。

Subtask 1 & 2

由于颜色块连续,当 query(l,r)==1 时必有 \([l,r]\) 的小球颜色全部相同。

于是双指针扫一遍即可,\(l\) 为当前颜色段起点,\(r\) 一直向右扫到 query(l,r)>1

namespace Subtask12{void solve(){int l=1,r=2,cnt=1;while(l<=n){while(r<=n&&query(l,r)==1) ++r;rep(i,l,r) ans[i]=cnt;++cnt,l=r;}cout<<"! ";rept(i,1,n) cout<<ans[i]<<' ';cout<<endl;}
}

Subtask 3 & 4

发现颜色数量不会超过 \(4\) 种。这里只需要考虑 \(4\) 种颜色的情况。

可以维护每种颜色最后出现的位置,按照最后出现的顺序排序,然后分讨即可,细节比较多。

namespace Subtask34{void solve(){int lst[5]={},ord[5];// lst[i]:颜色i上一次出现的位置rept(i,1,4) ord[i]=i;rept(i,1,n){sort(ord+1,ord+5,[lst](int x,int y)->bool{return lst[x]>lst[y];});int a=ord[1],b=ord[2],c=ord[3],d=ord[4];if(!lst[a]) ans[i]=1;else if(!lst[b]){if(query(lst[a],i)==1) ans[i]=a;else ans[i]=b;}else if(!lst[c]){if(query(lst[b],i)==3) ans[i]=c;else if(query(lst[a],i)==1) ans[i]=a;else ans[i]=b;}else{// 可以通过二分减少询问次数if(query(lst[b],i)==2){if(query(lst[a],i)==1) ans[i]=a;else ans[i]=b;}else{if(query(lst[c],i)==3) ans[i]=c;else ans[i]=d;}}lst[ans[i]]=i;}cout<<"! ";rept(i,1,n) cout<<ans[i]<<' ';cout<<endl;}
}

Subtask 5

先判断总颜色数量。

若为 \(N\),做法显然。

若为 \(N-1\),则有且仅有一对同色的球。

我们注意到如果 query(l,r)==r-l,则这对球一定在 \([l,r]\) 中。

因此从 \([1,N]\) 开始逐渐收紧区间就能找出同色球的位置。

namespace Subtask5{void solve(){int k=query(1,n);if(k==n){cout<<'!';rept(i,1,n) cout<<' '<<i;cout<<endl;return;}int l=1,r=n,cnt=1;while(l<=r&&query(l,r)==r-l) ++l;--l;while(l<=r&&query(l,r)==r-l) --r;++r;cout<<"! ";rept(i,1,n){if(i==l||i==r) cout<<n<<' ';else cout<<cnt++<<' ';}cout<<endl;}
}

Subtask 6 & 7

注意到,如果 query(l,r)==query(l+1,r),则 \([l+1,r]\) 中一定有与 \(l\) 同色的球。

有了这个,我们就能二分出每个球右边第一个与它同色的球的位置 \(nxt_i\),进而求出每个球的颜色。

namespace Subtask67{int nxt[N];// nxt[i]:i右边第一个与i同色的球位置void solve(){int cnt=1,p;rept(i,1,n){int l=i+1,r=n+1,mid;while(l<r){mid=l+r>>1;if(query(i,mid)==query(i+1,mid)) r=mid;else l=mid+1;}nxt[i]=l;}rept(i,1,n){if(!ans[i]){for(int j=i;j<=n;j=nxt[j]) ans[j]=cnt;++cnt;}}cout<<"! ";rept(i,1,n) cout<<ans[i]<<' ';cout<<endl;}
}

然而这样的询问次数大约是 \(2N\log_2 N\approx 20000\),过不了 Subtask 7。需要想办法去掉一次 query

发现 query(i,mid) 不好省掉,考虑省掉 query(i+1,mid)

仔细观察 query(i+1,mid),发现这个东西等于 \(mid-i-\sum_{k=i+1}^{mid}[nxt_k\le mid]\)

于是从 \(N\)\(1\) 倒着计算 \(nxt_i\),用树状数组维护和式里面的部分即可。

询问次数 \(N\log_2 N\),时间复杂度 \(O(N \log^2 N)\),目前最优解。

namespace Subtask67{int nxt[N],s[N];void add(int p,int x){while(p<=n){s[p]+=x;p+=p&-p;}}int ask(int p){int res=0;while(p){res+=s[p];p&=p-1;}return res;}void solve(){pert(i,n,1){int l=i+1,r=n+1,mid;while(l<r){mid=l+r>>1;if(query(i,mid)==mid-i-(ask(mid)-ask(i))) r=mid;else l=mid+1;}nxt[i]=l;if(nxt[i]<=n) add(nxt[i],1);}int cnt=1;rept(i,1,n){if(!ans[i]){for(int j=i;j<=n;j=nxt[j]) ans[j]=cnt;++cnt;}}cout<<"! ";rept(i,1,n) cout<<ans[i]<<' ';cout<<endl;}
}

完整代码

http://www.jsqmd.com/news/65257/

相关文章:

  • 仿生手的混合结构设计与神经形态触觉传感
  • P8272 [USACO22OPEN] Apple Catching G
  • 材料科学每日总结--Day13--数据挖掘
  • 原理图文档处理工具
  • P8187 [USACO22FEB] Robot Instructions S
  • 2025年3D扫描仪十大品牌权威排名:国产化替代首选TOP10
  • P8270 [USACO22OPEN] Subset Equality S
  • P6803 [CEOI 2020] 星际迷航
  • P8271 [USACO22OPEN] COW Operations S
  • P10779 BZOJ4316 小 C 的独立集
  • 街头徒手健身6倒立训练与肩部健康
  • AI语料优化新势力:助力企业抢占智能时代先机的优质服务商推荐
  • 基于MATLAB的位同步提取方法
  • Manim介绍
  • P2475 [SCOI2008] 斜堆
  • CF1970E3 Trails (Hard)
  • 双线性四边形等参单元程序(MATLAB实现)
  • 双线性四边形等参单元程序(MATLAB实现)
  • 102302141_易敏亮第四次数据采集作业
  • 李宏毅机器学习笔记41 - 实践
  • P6706 [COCI 2010/2011 #7] KUGLICE
  • P3596 [POI 2015 R3] 高速公路现代化 Highway modernization
  • AT_arc179_d [ARC179D] Portable Gate
  • AI Browser:我用 CC 做了个桌面版 Manus
  • P3576 [POI 2014] MRO-Ant colony
  • flink 1.20 物化表(Materialized Tables) - 详解
  • P4953 [USACO02FEB] Cow Cycling
  • CF700B Connecting Universities
  • 克服EMD端点效应的齿轮箱故障特征识别方法
  • 大模型算法学习