Codeforce 1982B Collatz Conjecture

假定每次整除平均需要 q q q 次,复杂度 O ( q n ) , q n ≥ 1 0 9 O(qn),qn\ge10^9 O(qn),qn109,显然不行。
出题人友好的用第三组样例提示了数组的循环性(我咋知道,他又没给完),加之题目背景和 3 n + 1 3n+1 3n+1 问题有关,所以也能和循环扯上关系,不妨从这个角度考虑。
既然题目背景有暗示,多测几组数据也能看出来(反正我是没看出来),这个数会在不断地迭代过程中变为 1,然后在 1 到 y − 1 y-1 y1 中循环。
下面推一下官解的公式:

  1. 第一步优化归一后的结果求解,这个循环的周期是 y − 1 y-1 y1,现在还剩 k k k 次计算,整个变化的数组长这样
    { x , ⋯   , 1 , ⋯   , y − 1 , 1 ⋯   , y − 1 } \{{x,\cdots,1,\cdots ,y-1,1\cdots ,y-1\}} {x,,1,,y1,1,y1}
    众所周知(我还真不是很知), k   m o d   y − 1 k\bmod y-1 kmody1 的取值是 { 0 , ⋯   , y − 2 } \{{0,\cdots,y-2\}} {0,,y2} ,所对应的值应当是 { 1 , ⋯   , y − 2 } \{{1,\cdots,y-2\}} {1,,y2},所以将剩余 k k k 次运算转化为结果就是(前提是 k k k 次运算后能够将给的 x x x 归一)
    a n s = 1 + k   m o d   ( y − 1 ) ans=1+k\bmod(y-1) ans=1+kmod(y1)
    不能归一的话怎么办呢,最简单的就是直接把这个时候的 x x x 输出,但是官解压行了,因为这时候 k = 0 k=0 k=0,显然有
    a n s = x + 0   m o d   ( y − 1 ) = x ans=x+0\bmod(y-1)=x ans=x+0mod(y1)=x
    合并两类,推出最终公式:
    a n s = x + k   m o d   ( y − 1 ) ans=x+k\bmod(y-1) ans=x+kmod(y1)
  2. 只做第一步优化连样例都过不了,因为数据给大之后凑整除需要的累加次数也会很大,很容易就超了,所以还要优化累加操作。
    比如要让 16 16 16 5 5 5 整除,很容易想到要凑 20 20 20,也就是说找到 5 5 5 16 16 16 后的一个倍数,首先确定 5 5 5 16 16 16 大约是 16 5 \frac{16}{5} 516 倍,显然下一个倍数就是 ⌈ 16 5 ⌉ × 5 = 20 \lceil\frac{16}{5}\rceil\times5=20 516×5=20,也就是说,每次直接加上
    o p = ⌈ x y ⌉ × y − x op=\lceil\frac{x}{y}\rceil\times y-x op=yx×yx
    就行了。
    当然如果这里使用 ceil 做取整运算还是超,因为这玩意其实是 double __cdecl ceil(double _X);,并非是对整型的运算,算多了效率挺低,因此数学代换一下就成了(当然这个除是整除):
    o p = ( x y + 1 ) × y − x op=(\frac{x}{y}+1)\times y-x op=(yx+1)×yx
    第一个公式单从数学意义上来说,对于 y ∈ Z , o p ≥ x ≥ 0 y\in Z,op\ge x\ge0 yZ,opx0 好像没问题,但不要忘了这是整除,会出现 x y = 0 \frac xy=0 yx=0 的情况,因此要确保每次至少加 1 1 1,同时还要确保每次累加操作不超过当前的剩余操作次数 k k k
    由于每次加都至少可以整除一次,所以每次操作至少将当前数减少
    ⌈ x + 1 y ⌉ , y ≥ 2 \lceil\frac{x+1}{y}\rceil,y\ge2 yx+1,y2
    显然时间复杂度优于二分,为 O ( log ⁡ n ) O(\log n) O(logn)
#include <bits/stdc++.h>
using namespace std;
template <typename A, typename B>
ostream &operator<<(ostream &os, const pair<A, B> &p)
{
    return os << '(' << p.first << ", " << p.second << ')';
}
template<typename C,typename D = typename enable_if <!is_same<C, string>::value,typename C::value_type>::type>
ostream &operator<<(ostream &os, const C &v)
{
    os << '{';
    string sep;
    for (const D &x : v)
        os << sep << x, sep = ", ";
    return os << '}';
}

void dbg_out()
{
    cerr << endl;
}
template <typename Head, typename... Tail>
void dbg_out(Head H, Tail... T)
{
    cerr << ' ' << H;
    dbg_out(T...);
}
#ifndef ONLINE_JUDGE
#define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__)
#else
#define dbg(...)
#endif

int ____________________CYCLE____________________;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define inf INT32_MAX
#define i64 int64_t
const int N = 1e5;

void solve(int cycle);

int main(){
#ifndef ONLINE_JUDGE
    freopen(".\\in.txt","r",stdin);
    freopen(".\\out.txt","w",stdout);
#endif
    ios::sync_with_stdio(false);
    std::cin.tie(0);


    int _=1;
    cin >> _;
    //cout << "Case #" << _ << ": " << endl;
    for(____________________CYCLE____________________=1;____________________CYCLE____________________<=_;____________________CYCLE____________________++){
        //cout << ____________________CYCLE____________________ << ":\n";
        solve(____________________CYCLE____________________);
    }
    
}
void solve(int cycle){
    int x,y,k;
    cin >> x >> y >> k;
    int cnt = 0;
    while(x != 1 && k > 0){
        //dbg(ceil(x / y) - x);
        int op = (x / y + 1)*y - x;
        op = max(1,op);
        op = min(op,k);
        //dbg(x);
        x += op;
        while(x % y == 0){
            x /= y;
            //dbg(x);
        }
        k -= op;
    }
    dbg(cycle,x,y,k);
    if(x == 1){
        int num = 1 + (k % (y-1));
        cout << num << endl;
    }else{
        cout << x << endl;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yyt363045841

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值