zoukankan      html  css  js  c++  java
  • 洛谷 P1660 数位平方和 记忆化暴搜

    更好的阅读体验

    Luogu传送门

    先来看看题意:

    定义(S(x))(x)各个数位上的数字的(k)次幂和((k)给定)。

    定义(h(x))为满足(h(x)leq min{x,h(s(x))})的最大值。

    (sum^r_{x=l} h(x) pmod {10^7+7})的值。

    (1leq l,r leq 10^6,1leq k leq 6)

    第一眼以为是一道数学题,看了几眼题面没看懂题意。

    那么让我们把这个看不懂(h(x))认真看看,其实就是要找到一个在不断的(x=s(x))过程中的最小的(x),即(min{x,s(x),s(s(x))...})。最大值三个字没啥用,因为是唯一的值。


    考虑递归,思考边界在哪里。

    (k)给定的情况下,相同的(x)所计算出来的(s(x))是一定的。所以当我们递归到已经出现过的数值的时候,就没必要在继续下去了。

    于是最终的思路就是不断的(x=s(x)),直到一个值出现第二次时,这条路上的最小值就是答案。

    但是不太友善的数据范围让我有点慌,于是加了个小小的优化:预处理每一个数字的(k)次方。

    然而..

    (经过了几次试探(vis)数组的大小),被卡在了#10

    再看看数据范围,仿佛明白了什么。

    同一个(s(x))可能会被多次用到,但同一个(h(x))不会。

    那么对(s(x))记忆化。

    然而现实又一次打败了我:我可怜的#10依然(TLE)

    有点慌了,跑去翻了翻题解,感觉没啥不同...

    可问题在于:我的(get\_s)是这么写的:

    int get_s(int x)
    {
    	if(s[x])return s[x];
    	int cnt=0;
    	while(x){cnt+=p[x%10];x/=10;}
    	return s[x]=cnt;
    }
    

    看上去好像没有问题。

    可细细看看最终的返回值,此时(x)必定(0),而程序不会(get\_x(0)),这会导致记忆化失效

    芜湖!

    int get_s(int x)
    {
    	if(s[x])return s[x];
    	int cnt=0,a=x;
    	while(x){cnt+=p[x%10];x/=10;}
    	return s[a]=cnt;
    }
    

    略改,一发入魂。


    (h(x))部分

    int work(int x)
    {
    	int res=x,k=x;
    	while(ap[k]!=x)
    	{
    		ap[k]=x;
    		k=get_s(k);
    		res=min(res,k);
    	}
    	return res;
    }
    

    ((ap)(vis)数组)

    这样写可以避免每次数组的清空。意思应该也很轻松能理解。

    整篇代码

    #include<bits/stdc++.h>
    using namespace std;
    int mod=1e7+7,ans=0;
    int p[10];
    int s[10000010];
    int ap[10000010];
    inline int min(int a,int b){return a<b?a:b;}
    int get_s(int x)
    {
    	if(s[x])return s[x];
    	int cnt=0,a=x;
    	while(x){cnt+=p[x%10];x/=10;}
    	return s[a]=cnt;
    }
    int work(int x)
    {
    	int res=x,k=x;
    	while(ap[k]!=x)
    	{
    		ap[k]=x;
    		k=get_s(k);
    		res=min(res,k);
    	}
    	return res;
    }
    int main()
    {
    	int k,l,r;
    	scanf("%d%d%d",&k,&l,&r);
    	for(int i=1;i<=9;i++)
    		p[i]=pow(i,k);
    	for(int i=l;i<=r;i++)
    		(ans+=work(i))%=mod;
    	printf("%d
    ",ans);
    	return 0;
    }
  • 相关阅读:
    Codeforces Round #627 (Div. 3) 总结
    [IOI1994] 时钟
    收集一些优秀的甲方安全开源项目
    python基础——对时间进行加减
    JSFinder:一个在js文件中提取URL和子域名的脚本
    python对齐输出
    python使用smtplib发送邮件
    任务2:扫描渗透测试(50分)[2019年信息安全管理与评估赛题答案-01]
    记一次Xmrig挖矿木马排查过程
    Bypass xss过滤的测试方法
  • 原文地址:https://www.cnblogs.com/moyujiang/p/13752049.html
Copyright © 2011-2022 走看看