DailyPractice

题源

题目

C. 平方
每次测试时间限制:2秒
每个测试的内存限制:256 MB
ikrpprpp 找到一个由整数组成的数组 a。他喜欢正义,所以他想要做到公平——也就是做到非减。为此,他可以对数组的索引 1 < i < n 执行正义行为,这会将 aż 替换为 a(位置 i 处的元素及其平方)。例如,如果 a = [2, 4, 3, 3, 5, 3] 并且 ikrpprpp 选择对 i = 4 执行正义行为,则 a 变为 [2, 4, 3, 9, 5, 3]。
最少需要多少次正义行为才能使数组不减?
输入
第一行包含一个整数 t (1 < t < 1000) 测试用例的数量。接下来是测试用例的描述。
对于每个测试用例,第一行包含一个整数 n a1, a2,…, an (1 ≤ a ≤ 10°)。数组a的大小。第二行包含 n (1 ≤ n ≤ 2105) 个整数
所有测试用例的 n 总和不超过 2 105。
输出
对于每个测试用例,打印使数组非递减所需的整数最小正义行为数。如果无法做到这一点,请打印 -1。

题目分析

初始思路
首先没办法之间从前往后跑一遍每次记录最大值,绝对会超,然后我一开始想的是预处理每一个arr[i]要翻多少翻能超过arr[i-1],或者要被前面那个arr[i-1]翻多少翻才能超越,然后把这些信息存储到新的数组中,后续利用该数组解决问题。
数学原理
传递性:
由于本题的数学特性
若 a r r [ i ] 2 a ≥ a r r [ i − 1 ] 2 b 则 b 每加上 x , a 至少也要加上 x 才能保持 该不等式继续成立 若arr[i]^{2^{a}}\geq arr[i-1]^{2^{b}}则b每加上x,a至少也要加上x才能保持\newline 该不等式继续成立 arr[i]2aarr[i1]2bb每加上xa至少也要加上x才能保持该不等式继续成立
因此本体每一个arr[i]对应的a是能够通过讨论arr[i]与arr[i-1]的关系以及讨论arr[i-1]的那个b来推算出来的,也就是说具有传递性。
P.S.我之前还有之后所说的所有“翻了多少翻”指的都是该不等式中a/b的值。
中有波折
奈何有一个细节处理 出了问题,一直没有用我的思想真正解决这道题
膜拜学习
后来看了tourist的代码,真是清晰简明啊,茅塞顿开,对于我原来的思路为何卡住同样有了理解,这个接下来再说。
成熟思路
首先找到第一个不是1的数,然后从该数字的下一个数字开始往后遍历,遍历途中如果遇到1就直接返回-1。
然后用last记录上一个数字翻了多少翻,cur计算该数字需要翻多少翻才能超过上一个数字,两个变量均保持为正数。然后考虑到该数字比上一个数字要大,可以在last的前提下不需要翻那么多次,也就利用到了之前所说的数学原理,让last减去k,k=上一个数字翻多少翻能超过该数字。
最终cur = cur +last;

解答

完整代码

premise code

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define For for (ll i = 1; i <= n; i++)
#define rFor for (ll i = n; i > 0; i--)
#define rep(i, sta, end) for (ll i = sta; i <= end; i++)
#define rrep(i, end, sta) for (ll i = end; i >= sta; i--)
#define All(x) for (auto item : x)

key code

inline void solve() {
	ll n;cin>>n;
	vector<ll> arr(n+10);
	For cin>>arr[i];
	ll sta=1;
	while(sta<=n&&arr[sta]==1){
		sta++;
	}
	ll cur=0,last=0,ans=0;
	rep(i,sta+1,n){
		if(arr[i]==1){
			cout<<-1<<endl;
			return;
		}
		ll x= arr[i];
		while(x<arr[i-1]){
			x*=x;
			cur++;
		}
		x= arr[i-1];
		while(last>0&&x*x<=arr[i]){
			x*=x;
			last--;
		}	
		//cout<<i-1<<"~"<<i<<" "<<cur<<" "<<last<<" "<<cur+last<<endl;
		cur += last;
		ans += cur;
		last = cur;
		cur=0;
	}
	cout<<ans<<endl;
}

算法分析

只需要O(n)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值