CF1408F Two Different 题解
CF1408F Two Different
给你 \(1\) 到 \(n\) 一共 \(n\) 个数的数组,给定一个函数 \(f(a,b)\),对于相同的 \(a,b\),函数 \(f(a,b)\) 的返回值相同(但是具体是什么你并不知道)。你每次可以选择两个位置的数并将他们变成 \(f(a,b)\)。请你找出若干个操作使得数组最后最多只有两个不同的数。
定义 \(g(x)\) 为将 \(x\) 个不同的元素变成相同元素的操作数。
可以发现 \(g(2^n)=2\times g(2^{n-1})+2^{n-1}\)。这个过程就是先将 \([1,2^{n-1}]\) 和 \([2^{n-1}+1,2^n]\) 两个区间的数变成相同的,然后再执行函数 \(f(i,i+2^{n-1})(i\in [1,2^{n-1}])\)。
所以对于 \(2\) 的整数次幂长度的区间我们最多只用 \(n\log_2 n\) 次操作推平。
则像 st 表一样,找到最大的 \(k\) 使得,\(2^k<n\),推平 \([1,2^k],[n-2^k+1,n]\) 即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int>ttfa;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
const int N=500005;
ttfa ans[N];int tot;
void solve(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
solve(l,mid);solve(mid+1,r);
for(int i=l;i<=mid;++i)
ans[++tot]={i,i+mid-l+1};
}
int main(){
int n=read(),k=1;
while(k*2<n)k*=2;
solve(1,k);solve(n-k+1,n);
printf("%d\n",tot);
for(int i=1;i<=tot;++i)
printf("%d %d\n",ans[i].first,ans[i].second);
return 0;
}
本文作者:BigSmall_En
本文链接:https://www.cnblogs.com/BigSmall-En/p/16662643.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
,
标签:
,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步