假定每次整除平均需要
q
q
q 次,复杂度
O
(
q
n
)
,
q
n
≥
1
0
9
O(qn),qn\ge10^9
O(qn),qn≥109,显然不行。
出题人友好的用第三组样例提示了数组的循环性(我咋知道,他又没给完),加之题目背景和
3
n
+
1
3n+1
3n+1 问题有关,所以也能和循环扯上关系,不妨从这个角度考虑。
既然题目背景有暗示,多测几组数据也能看出来(反正我是没看出来),这个数会在不断地迭代过程中变为 1,然后在 1 到
y
−
1
y-1
y−1 中循环。
下面推一下官解的公式:
- 第一步优化归一后的结果求解,这个循环的周期是
y
−
1
y-1
y−1,现在还剩
k
k
k 次计算,整个变化的数组长这样
{ x , ⋯ , 1 , ⋯ , y − 1 , 1 ⋯ , y − 1 } \{{x,\cdots,1,\cdots ,y-1,1\cdots ,y-1\}} {x,⋯,1,⋯,y−1,1⋯,y−1}
众所周知(我还真不是很知), k m o d y − 1 k\bmod y-1 kmody−1 的取值是 { 0 , ⋯ , y − 2 } \{{0,\cdots,y-2\}} {0,⋯,y−2} ,所对应的值应当是 { 1 , ⋯ , y − 2 } \{{1,\cdots,y-2\}} {1,⋯,y−2},所以将剩余 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(y−1)
不能归一的话怎么办呢,最简单的就是直接把这个时候的 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(y−1)=x
合并两类,推出最终公式:
a n s = x + k m o d ( y − 1 ) ans=x+k\bmod(y-1) ans=x+kmod(y−1) - 只做第一步优化连样例都过不了,因为数据给大之后凑整除需要的累加次数也会很大,很容易就超了,所以还要优化累加操作。
比如要让 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⌉×y−x
就行了。
当然如果这里使用ceil
做取整运算还是超,因为这玩意其实是double __cdecl ceil(double _X);
,并非是对整型的运算,算多了效率挺低,因此数学代换一下就成了(当然这个除是整除):
o p = ( x y + 1 ) × y − x op=(\frac{x}{y}+1)\times y-x op=(yx+1)×y−x
第一个公式单从数学意义上来说,对于 y ∈ Z , o p ≥ x ≥ 0 y\in Z,op\ge x\ge0 y∈Z,op≥x≥0 好像没问题,但不要忘了这是整除,会出现 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⌉,y≥2
显然时间复杂度优于二分,为 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;
}
}