Codeforces做题日记:拼尽全力终于是超时了

Codeforces Round 961 (Div. 2)  C. Squaring

首先,这道题目我费劲千辛万苦还是超时了,如果有大佬能进一步改进我的代码让它能过那就感激不尽了

先来看题目:

题目的大致意思就是:

对于一个给定的数组,你可以做如下操作:将某一个数变成它的平方,直到整个数组变成非递减的数组,求最小的操作次数

题目的要求非常简单,理解起来也很简单,很自然就能想到遍历一次,遇到比前一个小的就循环做平方直到比前一个大,但是用屁股也能想到这题不会这么简单就能做完,对一个数不断做平方的增长速度是非常快的,哪怕用double存都会超出范围,甚至都不需要几次操作就爆炸了,而且时间上也肯定过不了,那么我绞尽脑汁想出来了这么一个办法(尽管最后还是超时)(以下都是我当时的具体思考过程,有一些可能并不一定准确)

首先,应该要把整个数组都遍历一遍,因为你要找出所有不符合非递减的数,所以至少应该要是O(n)   ,那么怎么尽量把时间控制在O(n)还要能够避免计算过大的数字呢

我们来看:

如果我对某一个数x,进行了5次平方操作,最后的结果应该是,pow(5,pow(2,5)),那么如果我第二个数是一个比x大的数,经过相同次数的操作,一定会比它更大,那如果第二个数比x小呢,我们可以先进行a次平方操作,让它比x更大,然后再进行同样多次的平方操作就肯定会比前一个数大了,欸,这样我们就避免了所有结果会大于1e6的平方计算,所有数的计算次数也都只会小于5(对2进行5次平方操作的结果是4.294967e9,可以看到增长的非常快),这样时间复杂度就控制在O(5n)以内了,这样我只要记录每个数的原始值,和它最后经过了几次操作,这样遍历到下一个数的时候,只要先让下一个数增加到大于前一个数的原始值,再加上上一个数经过的操作数,就得到了这个数需要几次平方操作

解释以下为什么这样能得到最小的操作次数:通过对原始值进行比较,如a<b,那么对a,b进行同样次数的平方操作后得到A,B显然也是A<B,所以我要先经过x次平方操作让a>b,这里的x是通过循环得到的最小值,然后加上同样多的次数就可以让A>B了,如果次数可以减一,那么就意味着x-1次就可以让a<b。

我原以为通过这种方式避免大数的出现,还能将时间复杂度控制在O(n)已经能过了,谁知道还是过不了(而且这个代码应该是能被hack的,不知道大家能不能看出来,因为没有实际计算平方操作后的值,所以其实有点难判断第二个数有没有大于前一个数平方后的值,我最初是写了一个循环来计算平方后的值,(超出1e6的就break,因为题目规定元素不会超过1e6)但是超时了之后我又改了一下,这次是面向结果改的,没啥参考价值,而且百分百能被hack,更何况还是超时的)不知道有没有大佬可以帮忙再改一改,从这种思路出发有没有可能写出这道题目

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

int fun(int a)
{
	return a * a;
}

int main()
{
	int m = 0;
	cin >> m;
	while (m--)
	{
		int n=0;
		cin >> n;
		vector<int>arr(n);
		for (int i = 0; i < n; i++)
		{
			cin >> arr[i];
		}
		int count1=0;
		int num1 = arr[0];
		int sum = 0;
		int num2=arr[0];
		bool flag = true;
		bool flag2 = false;
		for (int i = 1; i < n; i++)
		{
			int count2 = 0;
			if (arr[i] <arr[i-1] || arr[i] <= fun(arr[i - 1]))
			{
				if (arr[i] == 1&&arr[i-1]!=1)
				{
					cout << -1 << endl;
					flag = false;
				}
				else
				{
					int temp = arr[i];
					while (arr[i] < num1)
					{
						arr[i] *= arr[i];
						count2++;
					}
					if (temp <= num1)
					{
						sum += count1 + count2;
						count1 += count2;
					}
					else if (temp >=fun(num1) && temp<fun(fun(num1)))
					{
						sum =sum+ count1 + count2 - 1;
						count1 = count1 + count2 -1;
					}
					num1 = temp;
				}
			}
			else
			{
				num1 = arr[i];
				count1 = 0;
			}
		}
		if(flag)
		cout << sum << endl;

	}

}

  • 20
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值