【代码源】每日一题 算的我头都大啦

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)) 

现在,要你求出 \sum_{i=1}^{m}g(m,i)的值。

 

为了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();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

self_disc

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

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

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

打赏作者

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

抵扣说明:

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

余额充值