[因吹斯汀结论]

  • 结论:设之前的位置为pre\_pos,然后删除位置坐标为的倍数的数,那么原来第pre\_pos个数的位置变为:now\_pos = pre\_pos - \lfloor \frac{pre\_pos}{y} \rfloor
的意思是有多少个的倍数,所以直接减去
  • now\_pos = pre\_pos - \lfloor \frac{pre\_pos}{y} \rfloor变形可以得到,意思是之前的位置等于现在的位置加上删除数字的个数
删除数字的个数等于,为什么是,因为如果,则算出来的一定不是的倍数,否则有可能是的倍数

故可以时间复杂度一步步算出pre\_pos:

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


void solve(){

    int x, y, k; cin >> x >> y >> k;
    if(y == 1){
        cout << "-1" << endl;
        return ;
    }
    for(int i = 1; i <= x; i ++){
        k = k + (k - 1) / (y - 1);
        if(k > 1000000000000){
            cout << "-1" << endl;
            return ;
        }
    }
    cout << k << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    cin >> tt;
    while(tt --) solve();
    return 0;
}

也可以用二分来做:上面的代码用的是,可以时间复杂度一步步算出pre\_pos。那也可以用now\_pos = pre\_pos - \lfloor \frac{pre\_pos}{y} \rfloor,因为满足单调性:

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;



int x, y, k;

bool check(int pos){
    for(int i = 1; i <= x; i ++) pos -= pos / y;
    if(pos >= k) return true;
    else return false;
}
void solve(){

    cin >> x >> y >> k;
    int l = 1, r = 1000000000000, ans = -1;
    while(l <= r){
        int mid = (l + r) / 2;
        if(check(mid)){
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    cout << ans << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    cin >> tt;
    while(tt --) solve();
    return 0;
}


第一段代码的时间复杂度为,第二段代码的时间复杂度为,在条件下都能通过
困难版本则是将的范围提升至次方
,这个公式原来是一次次推,所以时间复杂度为。但是累加的可能值相同,导致多次执行加上相同的数字,不如直接求次数,直接累加上,这样大大减少了时间复杂度
那么需要保证从开始累加了后,才会发生变化,所以累加了次后的仍然与一开始的值相同,所以有:
首先令,则
公式的计算.....

因为是整数,所以
解得,所以的最大值就为

核心代码:
如果了,那么无论加多少次,都灭有变化,进入死循环,所以推出
累加的次数不能超过,所以得与取最小值
如果,表示到达下一次的边界情况,仍然会死循环,所以设置,让其至少操作
然后位置累加,减去操作次数
while(x > 0){
    int t = (k - 1) / (y - 1);
    if(t == 0) break;
    int cnt = ((t + 1) * (y - 1) - k + t) / t;
    cnt = min(cnt, x);
    if(cnt == 0) cnt = 1;
    k += cnt * t;
    x -= cnt;
    if(k > 1000000000000){
        cout << "-1" << endl;
        return ;
    }
}


总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


void solve(){

    int x, y, k; cin >> x >> y >> k;
    if(y == 1){
        cout << "-1" << endl;
        return ;
    }
    while(x > 0){
        int t = (k - 1) / (y - 1);
        if(t == 0) break;
        int cnt = ((t + 1) * (y - 1) - k + t) / t;
        cnt = min(cnt, x);
        if(cnt == 0) cnt = 1;
        k += cnt * t;
        x -= cnt;
        if(k > 1000000000000){
            cout << "-1" << endl;
            return ;
        }
    }
    if(k > 1000000000000) cout << "-1" << endl;
    else cout << k << endl;
    return ;
}

signed main(){
    HelloWorld;

    int tt = 1; 
    cin >> tt;
    while(tt --) solve();
    return 0;
}