CF1408F Two Different 题解
解题思路
先考虑如何将一堆数变为相同的。
显然,这里有一个条件
- 每次操作只能将两个数变为相同的,那么一个数在使得其他数变为相同数的操作中(我们不妨将所有数进行这种操作称为一轮操作),一个数最多被使用一次;
- 按照错位操作,即第一轮
和 、 和 ,第二轮 和 、 和 这种最优决策(这样可以保证每一轮结束后不同数的数量最少)每一轮也最多减少 种数量; - 按照如上方法,在第
轮会有 的数无法被操作到,那么当且仅当 的时候,所有数可以变为相同的;
由上可以推出,当且仅当
那么考虑
由于我们在使一个序列相同时错位操作,那么每个数在一轮中会被恰好操作一次,又由于每轮操作会使不同的数的数量减半,那么最多进行
时间复杂度
注意事项
错位操作时细节有亿点多,如果是循环写法,一定要注意倍增的时候不要超出
AC 代码
#include<stdio.h>
#include<stdlib.h>
#include<vector>
#define N 15005
#define pii std::pair<int,int>
int n,cnt,c[N];
std::vector<pii> ans;
std::vector<int> a[N],b[N];
inline void print(){
printf("%d\n",ans.size());
for(auto now:ans){
int x=now.first;
int y=now.second;
printf("%d %d\n",x,y);
}
}
inline void GetAns(int l,int r){
int m=r-l+1,now=2;while(m>1){
for(register int i=l;i<=r;i+=now)
for(register int j=i;j<i+(now>>1);++j)
ans.push_back({j,j+(now>>1)});
m>>=1;now<<=1;
}
}
signed main(){
scanf("%d",&n);
for(register int i=1;i<=n;++i)
c[i]=i;int mid=1;
while((mid<<1)<n) mid<<=1;
GetAns(1,mid);
GetAns(n-mid+1,n);
print();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下