题目概述

原题参考:C. Divisor Chain
给出一个数x,可以对他做以下的变换

  • 若y是x的除数,x-=y
  • 任意的y不能使用超过两次
    可以证明的是,对于任意的数,都可以在1000次操作内将其变成1,请输出将x变为1的操作次数与过程

思路想法

首先是如果随机除以因子的话,那么肯定会很麻烦,因为求因子麻烦,记录因子的使用次数也麻烦,那么就想如何快速的给出因子,而且最好是不一样的,正常的十进制不好做,思考二进制的转化,由此可以得到触发,二进制的最后一位1以后的数是这个数的因子,因此我们可以将任意一个数转化为2的次方,转化为2的次方之后,出现一个问题,如何将其转化为1?毫无疑问,这是不好做的,但是我们很容易将一个2的次方转化为2,再用2转化为1,然后再来思考是否满足题目的第二个要求,明显,对于任意一个因子,只可能最多使用两次(降为2次方一次,降为1一次);至于1000次操作以内,那更是绰绰有余,题目的范围是1e9,“右移”最多32次,“左移”最多32次

参考代码

#include <bits/stdc++.h>
using namespace std;
#define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define pll pair<long long, long long>
#define pii pair<int, int>
#define vi vector<int>
#define vl vector<long long>
#define ll long long
#define ull unsigned long long
const ll INF = 9187201950435737471;
const int inf = 2139062143;
const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1.0);
ll x;
ll lowbit(ll x) {return x&-x;}
void solve() {
    ll cnt = 0;
    vector<ll> ans;
    cin >> x;
    ans.push_back(x);
    while(x-lowbit(x)) {
        x -= lowbit(x);
        ans.push_back(x);
    }
    while(x != 2) {
        x >>= 1;
        ans.push_back(x);
    }
    ans.push_back(1);
    cout << ans.size() << endl;
    for(auto x:ans) cout << x << " ";
    cout << endl;
}
int main() {
#ifdef xrl
    freopen("in.txt", "r", stdin), freopen("out.txt", "w", stdout);
#endif
    FAST_IO;
    int t = 1;
    cin >> t;
    while(t --) solve();
#ifdef xrl
    cout << "Time used = " << (double)(clock() * 1.0 / CLOCKS_PER_SEC) << "s";
#endif
    return 0;
}

做题反思

记录一下,这是第一个10分钟以内昨晚的c题hhh,今天的爽局,对于数字转化的题目,如果十进制想不到好办法,可以转化为二进制思考,二进制的因子很好用

posted on 2024-03-07 23:30  山余木  阅读(12)  评论(0)    收藏  举报