国庆测试-one Problems Explanation

前言

差点一套把我直接送走
60+0+0+40=100…


Problem 1 数列问题

题目描述
小明和小红在一起玩游戏,小明觉得现在玩的游戏太无聊了,便给小红出了一道数列问题。数列问题的题目如下:

一开始,小明给小红一个只含有数字1的数列,接下来,小红可以对这个数列进行以下操作中的一种操作:

· 对序列中已有的一个元素加1.

· 复制一个序列中已有的元素到序列的末尾.
比如:一开始序列中只有一个元素[1]

我们可以选择这个序列中的第一个元素进行第二种操作,即复制操作,这样,这个序列就变成了[1,1]

然后,我们可以对这个序列中的第一个元素进行第一种操作,即将第一个元素进行+1.这样,这个序列就变成了[2,1]

现在,小明问小红,她最少需要进行多少次操作,可以使得序列中所有元素的和至少为n。

小红面对小明的这个问题一脸懵逼,于是,她来求助聪明的你,希望你能够帮助她解决这个问题。

输入格式
第一行一个数字t,表示测试数据的组数。

接下来行,每行一个数字,表示序列所有元素和至少应该达到的数。

输出格式
对于每一个问题,回答一个数字,表示小红最少需要操作的次数。

样例
样例输入:
5
1
5
42
1337
1000000000
样例输出:
0
3
11
72
63244


手推数据,发现规律为:0,1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,7,7,7,7…
Solution1:map暴力枚举处理每个循环节开始的数,再在查询时找1~1e9中的
数,第一个大于等于它的数的操纵数即为答案,O(1e9t),再用一个map映射原数的话O(63244t) TLE 60
Solution2:公式,我不会证,但能想到成次方增加最优

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
   
	int t,n;
	scanf("%d",&t);
	while(t--)
	{
   
		scanf("%d",&n);
		int k=0;
		for(int i=1;i<=n;i++)
		{
   
			if(i*i>=n)
			{
   
				k=i;
				break;
			}
		}
		if(k*(k-1)>=n)
		{
   
			printf("%d\n",k*2-3);
		}
		else{
   
			printf("%d\n",2*k-2);
		}
	}
	return 0;
}

手推公式的题还是第一次考啊。。。


Problem 2 Teamwork

传送门
考试时没想到怎么处理两个组之间的数的所属,打了个假贪心,WA 0

Solution:设d[i]表示到i时能获得的最大价值,因为它所属的组最多从max(0,i-k+1)开始,min(n,i+k-1)结束,与其他元素无关,又因为i+k-1会被后面的数的前一部分统计到,所以只考虑前一部分

则dp[i]=max(dp[i],dp[j]+maxn*(i-j))
其中 (上一组最后一个)i-k<=j<=i-1
maxn表示组内最大值,用RMQ优化

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int maxn,n,k,a[10005],dp[10005],f[100005][20];
void ST_chushi()
{
   
	for(int i=1;i<=n;i++)
	{
   
		f[i][0]=a[i];
	}
	int t=(int)(log(n)/log(2))+1;
	for(int j=1;j<t;j++)
	{
   
		for(int i=1;i<=n-(1<<j)+1;i++)
		{
   
			f[i][j
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值