2022.05.23
题目链接:算的我头都大啦 - 题目 - Daimayuan Online Judge
题目描述:
爱数学的小明又回来辣!看了上次大家解决问题的方法后觉得自己实在是太笨了,同时引来了同是数学爱好者的小红的嘲笑,自尊心极强的小明气不过,便和小红打个赌,让小红出一道数学题给小明写,如果小明能在一周内写出来,小红就请他吃下个星期的疯狂星期四,如果做不出来就要小明请她疯狂星期四。
但是这道题实在是太难啦,小明把自己关在房间里想了一周也没能想出来,明天就是赌约的截止日期了,小明非常想吃KFC,于是他想到了再次向你求助,并承诺只要帮他写出这道题就把小红请的KFC分你一半。
小红设立了两个函数 f(x)和g(x,m) .
f(x)的定义如下:
比如:f(2013)=(2013∗13∗13∗3)mod2014
g(x,m)的定义如下:
比如g(x,2)=f(f(x))
现在,要你求出 的值。
为了KFC,拼了!
输入格式
第一行有一个数T (1≤T≤20),代表一共有TT组数据。 接下来TT行有两个数x,mx,m(1≤x,m≤10^9),代表g(x,m)的两个参数
输出格式
对于每行测试例输出一个数字。
样例输入
2
3 4
4102 642
样例输出
12
21262
分析:
由g(x,m)函数结合递归可知需要求m次f(x),x和m的范围都到了10^9,暴力枚举肯定不行。随便拿个数模拟的时候你会发现到最后都会到达x=f(x) 的情况,就是之后就f(x)的值不再改变了。当x=f(x)时就可以直接累加,及时退出循环。
那么为什么会有x=f(x)的情况呢?为什么在最差的情况下不会超时呢?因为每次求f(x)后会对(x+1)取模,结果等于x的话就直接满足x=f(x)了,不等的话f(x)一定是小于x的,也就是f(x)的值在不断的减小,并且不可能回到之前的值,也就是说f(x)的值只会减小直到相等。很容易知道x为个位数的时候f(x)=x,让后中间也会有满足f(x)=x的x,例如21,51,301……复杂度肯定还是够的。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll x, m;
ll f(ll x)
{
ll ans = 1;
ll base = 1;
while (x >= base)
{
base *= 10;
ans = ans * (x % base); //从低位依次取出每个要累乘的数
}
return ans % (x + 1); //返回f(x)
}
void solve()
{
cin >> x >> m;
ll ans = 0;
while (m--)
{
x = f(x);
ans += x;
if (x == f(x))
{
ans += m * x; //之后的m次的值均为x
cout << ans << "\n";
return;
}
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
solve();
}
}