https://codeforces.com/contest/1469/problem/D
这题观察发现一个比较优的策略
我们选择一个基数c,然后让n/(n/c), (n/c)/(n/c/c)....这样下去,把这些数字都变成c,然后最后再来一遍用c把他们变成1,最后用2把c变成1,那么最后就剩2这个2了,其他都是1
其他不在这中间考虑的数字我们就首先让他们全部/n变成1
所以对于3-n这些数字,只有c要让他不断/2,然后 n/c,n/c/c这些数字要先变c再变1,其他的数字都是1次变1,
所以这题本质上就是让log_c{n}+log_2{c}最小
数学基础扎实的人一下就会了,隔壁家20多岁还在打数理基础的叔叔研究了好久呜呜呜呜,可千万不要学我
最后试出来c=8在n=2e5下是可行的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,k,cnt,tot,cas;
int a[maxl];
bool vis[maxl];
char s[maxl];
typedef pair<int,int> p;
vector<p> ans,ans2;
inline void prework()
{
scanf("%d",&n);
// n=2e5;
for(int i=1;i<=n;i++)
vis[i]=false;
ans.clear();
int c=8,now=n,nxt;cnt=0;
if(n<c)
{
for(int i=3;i<n;i++)
ans.push_back({i,n});
now=n;
while(now>1)
now=now/2+(int)(now%2!=0),ans.push_back({n,2});
return;
}
while(1)
{
if(now<=c)
break;
vis[now]=true;
a[++cnt]=now;
nxt=now/c;
if(now%c!=0)
nxt+=1;
now=nxt;
}
a[++cnt]=c;
vis[c]=true;
for(int i=3;i<n;i++)
if(!vis[i])
ans.push_back({i,n});
for(int i=1;i<cnt;i++)
ans.push_back({a[i],a[i+1]});
for(int i=1;i<cnt;i++)
ans.push_back({a[i],c});
now=c;
while(now>1)
now=now/2+(int)(now%2!=0),ans.push_back({c,2});
}
inline void mainwork()
{
}
inline void print()
{
tot=ans.size();
printf("%d\n",tot);
for(p d:ans)
printf("%d %d\n",d.first,d.second);
}
int main()
{
int t=1;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}