题解 | #F #
向上取整
https://ac.nowcoder.com/acm/contest/21041/F
F题不难!!!!
思路:把1~n的数挑出几个重要的数字
- 2的0次方 1
- 2的1次方 2
- 2的2次方 4
- 2的4次方 16
- 2的8次方 256
- 2的16次方 65536
- n
发现
- 可以发现每个下面的数字对上面的数字进行两次向上取整 就会变成1;
- 其余不是这几个数字的数,只要与n(最大的数)做一次向上取整就会变成1;
解决方法
先让非重要数字与n进行操作变成1,再让重要的数字从下向上依次进行两次操作变成1。
最多操作次数应该为n+3.
代码
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define sc(x) scanf("%d",&x)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
typedef pair<int,int> pa;
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; }
ll qpow(ll a, ll b, ll mod) { ll ans = 1; a%=mod; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; }
const int mod=1e9+7;
const int N=1e5+7;
ll n;
int f[7]={0,1,2,1<<2,1<<4,1<<8,1<<16}; /*重要数字*/
vector<pa>ans;
int main(){
//freopen("in.txt","r",stdin);
//freopen("output.txt","w",stdout);
int t;
cin>>t;
while(t--){
ans.clear();
cin>>n;
/*找出n所在的范围*/
int pos=2;
for(pos;pos<=6;pos++){
if(f[pos]>n) break;
}
pos--;
/*非重要数字与n进行操作*/
for(int i=3;i<n;i++){
if(i==4||i==(1<<4)||i==(1<<8)||i==(1<<16)) continue;
ans.push_back(make_pair(i, n));
}
/*如果n与重要数字相同*/
if(n!=f[pos]){
ans.push_back({n,f[pos]});
ans.push_back({n,f[pos]});
}
/*把重要数字依次与上一个重要数字进行两次操作*/
for(pos;pos>=3;pos--){
ans.push_back({f[pos],f[pos-1]});
ans.push_back({f[pos],f[pos-1]});
}
cout<<ans.size()<<endl;
for(auto it : ans) printf("%d %d\n",it.first,it.second);
}
return 0;
}