[蓝桥杯][2016年第七届真题]冰雹数(暴力打表找规律)

题目描述
任意给定一个正整数N,
如果是偶数,执行: N / 2
如果是奇数,执行: N * 3 + 1

生成的新的数字再执行同样的动作,循环往复。

通过观察发现,这个数字会一会儿上升到很高,
一会儿又降落下来。
就这样起起落落的,但最终必会落到“1”
这有点像小冰雹粒子在冰雹云中翻滚增长的样子。

比如N=9
9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1
可以看到,N=9的时候,这个“小冰雹”最高冲到了52这个高度。
输入
一个正整数N(N<1000000)
输出
一个正整数,表示不大于N的数字,经过冰雹数变换过程中,最高冲到了多少。
样例输入
10
样例输出
52
思路:在dotcpp上,就算是不暴力也一样可以过,但是总感觉不是很对。时间还是有点多。
我的做法是暴力打表,保存1-1000000的值。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=1e6+100;
map<ll,ll> dp;
int n;

inline ll dfs(ll u)
{
	if(dp[u]!=0) return dp[u];
	if(u==1) return dp[u]=1ll;
	ll _max;
	if(u&1) _max=u*3ll+1ll;
	else _max=u/2ll;
	_max=max(_max,dfs(_max));
	return dp[u]=_max;
}
int main()
{
	scanf("%d",&n);
	ll _max=0;
	freopen("out.txt","w",stdout);
	for(int i=1;i<=n;i++) 
	{
		_max=max(dfs((ll)i),_max);
		printf("%lld ",_max);
	}
	return 0;
}

打表如图:
在这里插入图片描述
我门可以发现很多重复的。
那么我们把所有重复的区间找出来就可以O(1)查询了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=1e6+100;
map<ll,ll> dp;
int n;

int main()
{
	ll _max=0;
	freopen("out.txt","r",stdin);
	ll l=1,r,x;
	ll pre=1;
	for(ll i=1;i<=1000000;i++) 
	{
		scanf("%lld",&x);
		if(i==0) continue;
		if(x==pre) r=i;
		else
		{
			printf("else if(n>=%lld&&n<=%lld) cout<<%lldll<<endl;\n",l,r,pre);
			pre=x,l=r=i;
		}
	}
	printf("else if(n>=%lld&&n<=%lld) cout<<%lldll<<endl;",l,r,pre);
	return 0;
}

最后就是正式代码了:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll n;

int main()
{
	scanf("%d",&n);
	if(n>=1&&n<=2) cout<<1ll<<endl;
	else if(n>=3&&n<=6) cout<<16ll<<endl;
	else if(n>=7&&n<=14) cout<<52ll<<endl;
	else if(n>=15&&n<=26) cout<<160ll<<endl;
	else if(n>=27&&n<=254) cout<<9232ll<<endl;
	else if(n>=255&&n<=446) cout<<13120ll<<endl;
	else if(n>=447&&n<=638) cout<<39364ll<<endl;
	else if(n>=639&&n<=702) cout<<41524ll<<endl;
	else if(n>=703&&n<=1818) cout<<250504ll<<endl;
	else if(n>=1819&&n<=4254) cout<<1276936ll<<endl;
	else if(n>=4255&&n<=4590) cout<<6810136ll<<endl;
	else if(n>=4591&&n<=9662) cout<<8153620ll<<endl;
	else if(n>=9663&&n<=20894) cout<<27114424ll<<endl;
	else if(n>=20895&&n<=26622) cout<<50143264ll<<endl;
	else if(n>=26623&&n<=31910) cout<<106358020ll<<endl;
	else if(n>=31911&&n<=60974) cout<<121012864ll<<endl;
	else if(n>=60975&&n<=77670) cout<<593279152ll<<endl;
	else if(n>=77671&&n<=113382) cout<<1570824736ll<<endl;
	else if(n>=113383&&n<=138366) cout<<2482111348ll<<endl;
	else if(n>=138367&&n<=159486) cout<<2798323360ll<<endl;
	else if(n>=159487&&n<=270270) cout<<17202377752ll<<endl;
	else if(n>=270271&&n<=665214) cout<<24648077896ll<<endl;
	else if(n>=665215&&n<=704510) cout<<52483285312ll<<endl;
	else if(n>=704511&&n<=1000000) cout<<56991483520ll<<endl;
	return 0;
}

虽然暴力可以过,但是更正规一点的比赛应该不会出现数据水的情况,所以还是需要更准确一点的。
努力加油a啊,(o)/~

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

starlet_kiss

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

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

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

打赏作者

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

抵扣说明:

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

余额充值