首页 > 其他分享 >题解:P1660 数位平方和

题解:P1660 数位平方和

时间:2024-10-14 18:43:58浏览次数:9  
标签:数位 定义 题解 ll P1660 平方和 Step include Rightarrow

Problem Link

Step 1:

“定义 \(S(n)\) 表示 \(n\) 个的各个数位的 \(k\) 次方的和。”

数位的 \(k\) 次方,我们可以通过快速幂求出,为了节省时间,我们可以定义一个 \(a\) 数组,来表示 \(0\sim9\) 区间中各数字 \(k\) 次方的值。

然后我们通过定义一个 \(s\) 数组来存储 \(0\sim4\times10^{6}\) 区间中各数字的 \(S\) 值。

Step 2:

“定义 \(H(n)\) 为满足 \(H(n) \le \min\{n, H(S(n))\}\) 的最大值。“

关于这个,不难想到通过递归求出 \(H(n)\) 的值。

但是,进行手动模拟后不难发现,有些时候直接将 \(H(i)=\min{n,H(S(i))}\) 会造成死循环。

例子:当 \(k=2\),\(n=2\) 时,求 $ H(2)$ 即求 $ H(4) \Rightarrow H(16) \Rightarrow H(37) \Rightarrow H(58) \Rightarrow H(89) \Rightarrow H(145) \Rightarrow H(42) \Rightarrow H(20) \Rightarrow H(4) \Rightarrow H(16) \dots $ 

显然,这形成了一个环,此时不难想到“环上最小值就是整个环相同 \(H\)。”

所以我们可以通过定义一个 \(mark\) 数组来表示个点的访问次数,若 mark[i]==2 则说明出现了环,那你就再走一次去寻找并更新环上最小值。

这时不难想到通过定义一个 \(h\) 数组来实现记忆化搜索,又省了一些时间。

Step 3:

此时你会发现题目已经做完,剩下仅需处理一些细节同时略微整合一下代码便可以 \(\color{black}\texttt{AC}\) 了。

//written by naught
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<climits>
using namespace std;

typedef long long ll;
#define Maxn 4000005 //4倍空间
#define Mod 10000007

inline ll read(ll x=0,bool f=0,char c=getchar()){while(!isdigit(c))f=c=='-',c=getchar();while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return f?-x:x;}

ll k,A,B,m;
ll ans;
ll a[12],s[Maxn],h[Maxn],mark[Maxn];

ll hts(ll x,ll y) //快速幂
{
    m=1;
    while(y)
    {
        if(y%2==1)
        {
            m*=x;
            m%=Mod;
        }
        x*=x;
        x%=Mod;
        y/=2;
    }
    return m;
}

ll S(ll x) //求S
{
    m=0;
    while(x)
    {
        m+=a[x%10];
        m%=Mod;
        x/=10;
    }
    return m;
}

ll H(ll x) //求H
{
    if(h[x]) return h[x]; //记忆化搜索
    if(mark[x]==2) return x;
    ++mark[x];
    h[x]=min(x,min(s[x],H(s[x]))); //处理环
    --mark[x];
    return h[x];
}

int main()
{
    k=read(),A=read(),B=read();
    for(ll i=0;i<10;++i){
        a[i]=hts(i,k);
    }
    for(ll i=0;i<Maxn;++i){
        s[i]=S(i);
    }
    h[0]=0;
    h[1]=1;
    for(ll i=A;i<=B;++i){
        ans+=H(i);
        ans%=Mod; //勿忘取模
    }
    printf("%lld",ans);
    return 0;
}

标签:数位,定义,题解,ll,P1660,平方和,Step,include,Rightarrow
From: https://www.cnblogs.com/naughty-naught/p/18464763

相关文章

  • 题解:P7356 「PMOI-1」游戏
    ProblemLink「PMOI-1」游戏题意给你一个胜利规则为黑白白白的棋类游戏,你执白,黑先行且第一步必下\((0,0)\),双方皆可放弃落子且落子坐标必须为自然数,请在4步内获胜。思路在自己与自己对下几局之后,有几个显然的发现:黑棋会尽量阻止你4步获胜。在你不会再下一步就获......
  • 题解:AT_agc027_b [AGC027B] Garbage Collector
    ProblemLink[AGC027B]GarbageCollector题意原题翻译已经很不错了,这里不再赘述。思路推论:每次取的垃圾数量应尽可能均分。证明如图,假设有\(4\)个垃圾需要被捡起,有两种取法:取一号垃圾+取二三四号垃圾。取一二号垃圾+取二三号垃圾。前者所需能量为:\(\display......
  • [2024领航杯] Pwn方向题解 babyheap
      [2024领航杯]Pwn方向题解babyheap前言:当然这个比赛我没有参加,是江苏省的一个比赛,附件是XiDP师傅在比赛结束之后发给我的,最近事情有点多,当时搁置了一天,昨天下午想起来这个事情,才开始看题目,XiDP师傅说是2.35版本的libc,确实高版本libc的却棘手,我经验太浅了调试半天,最后让我们......
  • CF360B题解
    简述题意定一个数列\(a\),可以对其中的元素做至多\(k\)次修改,每次修改可以将数列中的一个数改成另一个。求经过修改后,\(max_{i=1}^{n}|a_i-a_{i-1}|\)思路考虑二分答案,对于check函数,我们可以利用dp进行求解。由于修改不太好想,我们可以把问题转换为让不被修改的数最多......
  • CF1814B. Long Legs 题解 枚举
    题目链接:https://codeforces.com/problemset/problem/1814/B题目大意有一个无限大的二维平面,我们用\((x,y)\)来表示平面中横坐标为\(x\)纵坐标为\(y\)的那个位置。一个机器人被放置在该二维平面的\((0,0)\)位置中。该机器人的腿长可以调节。最初,它的腿长为\(1\)。......
  • 【题解】Solution Set - NOIP2024集训Day50 图的连通性相关
    【题解】SolutionSet-NOIP2024集训Day50图的连通性相关https://www.becoder.com.cn/contest/5618「JSOI2012」越狱老虎桥简述题意:题目大意:给定一张图,A先添加\(1\)条边,B再删去一条边使得图不连通,A要最大化删除边的权值,B要最小化删除边的权值,问最终的权值是多少。......
  • qoj8528 Chords 题解
    数据随机有什么用?用你惊人的注意力可以观察到答案的值域在\(800\)附近。考虑暴力dp,设\(dp_{l,r}\)表示值域在\([l,r]\)中最多能选几个区间。假设\(r\)对应区间的左端点为\(lst\),那么有转移方程\(dp_{l,r}=dp_{l,lst-1}+dp_{lst+1,r-1}+1\)。时间复杂度\(O(n^2)\)。......
  • Codeforces Round 978 (Div. 2) A-D1 题解
    我的同学还在VP,排名马上放声明:不要觉得有subtask的题目只做Easyversion没有意义,从这里也能捞很多分,况且有的时候并不是简单和难的区别,而是考不同的算法A.BustoPénjamo题意有一辆车上面有$r$排座位,每排有$2$个座位,现在共$n$个家庭出行坐公交车,每个家庭$a_i$......
  • 洛谷 P2071 座位安排题解
    因为一个人坐一个座位很像二分图,题意转化为二分图最大匹配。把人放在左部,把座位放在右部,一排座位占右部的两个点。假设人想要坐在\(x\)排,那么建图的时候就可以将这个人连向\(2x\)和\(2x+1\)。这样一排就对应着两个人了。由于\(n\le4000\),直接由朴素的\(O(nm)\)的匈牙利......
  • 【题解】CEIT 2024 第三周算法训练 讲义题解
    A.Orange的作文排版关于处理若干行输入,我们可以用while结合getline函数来完成,每次读取一行,就让行数+1,然后每次利用string的size方法得到当前行的列数,更新最长的列,最后得到答案。#include<bits/stdc++.h>usingnamespacestd;intmain(){strings;inta=0;i......