当前位置: 首页 > 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.zskr.cn/news/75798.html

相关文章:

  • 材料科学每日总结--Day13--数据挖掘
  • 原理图文档处理工具
  • 2025年3D扫描仪十大品牌权威排名:国产化替代首选TOP10
  • P8270 [USACO22OPEN] Subset Equality S
  • 街头徒手健身6倒立训练与肩部健康
  • 基于MATLAB的位同步提取方法
  • 102302141_易敏亮第四次数据采集作业
  • CF700B Connecting Universities
  • P6875 [COCI2013-2014#6] KRUŽNICE
  • 北京上门回收名家字画 专访北京丰宝斋负责人徐亚南
  • MultiButton移植记录
  • Excel 公式
  • P6173 [USACO16FEB] Circular Barn P
  • 为数字文明奠基:论通译院-价值星图-叙事舞台架构作为价值实践的元操作系统
  • grep 常用功能
  • 2025 最新工业自动化服务商 / 厂家 TOP5 评测!科技赋能 + 全周期服务权威榜单发布,引领智慧工厂建设新生态
  • 2025 最新智慧工厂建设服务商/厂家 TOP5 评测!科技赋能+全周期服务权威推荐榜单发布,引领智能制造新生态
  • why windows is worst
  • 4pcs Launch LTR-05 TPMS Sensor Tool 315MHz 433MHz - Metal/Rubber for European/American Cars
  • Get Lifetime Free Launch X431 ADAS Calibration for PAD VII/Pro5/Pro3S+/Pro3/APEX
  • 儿童补钙不盲选!从钙源到配方,儿童钙剂选购全指南
  • 2025年ChatGPT优化排名公司推荐:AI驱动下的SEO新选择
  • 2025年深圳GEO优化公司推荐:AI驱动时代的流量突围伙伴
  • 2025年11月儿童营养品牌测评指南——选对不踩坑
  • 【AI大模型技术】2.神经网络 - 教程
  • P3120 [USACO15FEB] Cow Hopscotch G
  • ABC435
  • 散修带你入门鸿蒙应用开发基础:启程篇(上) - 鸿蒙
  • 分库分表是同一个实例内的多个不同库/不同表吗
  • Launch X431 PRO Elite: Full System CAN FD Active Tester OBD2 Scanner for Euro/American Cars