洛谷 P8918 『MdOI R5』Jump 题解

题目传送门

这一题其实很简单,只是要想到正确方法

我一开始用了奇怪的搜索

①无解的情况:

看上去很离奇,实际上略加思索就会发现,如果输入 n n n 为偶数,那么就铁定无解。证明过程如下:

n   m o d   2 = 0 n\bmod{2}=0 nmod2=0,人距离 n n n 点的距离为 d i s dis dis ,则当走出第一步(步长为 1 1 1)时,有:
d i s = ∣ n ± 1 ∣ dis=\mid n\pm1\mid dis=∣n±1
所以:
d i s ≡ 1 ( m o d i ) dis\equiv1\pmod{i} dis1(modi)
k k k 为正整数且满足 k > 1 k > 1 k>1 ,显然有:
2 k ≡ 0 ( m o d 2 ) 2^k \equiv0\pmod{2} 2k0(mod2)
因此,在走出第一步后无论怎么走也到达不了奇数的距离,即无法走到 n n n 点。

②有解的情况

似乎是一道走路问题,实际上我们可以把向左走看成减法,把向右走看成加法,那么题目就转化成了:

有一个正整数 n n n,试回答 n n n 是否满足如下式子:

n = ⋆ 2 0 ⋆ 2 1 ⋆ . . . . . . ⋆ 2 k n=\star2^0\star2^1\star......\star2^k n=2021......2k

如果不满足,则输出 − 1 -1 1,否则输出 k k k ( k ∈ N + ) (k\in \mathbb N_+) (kN+),其中" ⋆ \star "处可以填正号或负号使式子成立

那么我们观察数据,手算几个,就可以发现:
1 = 2 0 1=2^0 1=20
3 = 2 0 + 2 1 3=2^0+2^1 3=20+21
5 = − 2 0 + 2 1 + 2 2 5=-2^0+2^1+2^2 5=20+21+22
. . . . . . ...... ......
规律很难找,但是我们发现不管怎么样,都有 n ≤ ∣ ⋆ 2 0 ∣ + ∣ ⋆ 2 1 ∣ + . . . . . . + ∣ ⋆ 2 k ∣ n\le\mid\star2^0\mid+\mid\star2^1\mid+......+\mid\star2^k\mid n≤∣20+21+......+2k, (“ ⋆ \star "意义如上所述),这其实很好解释,因为如果不满足这个关系式,那么就算” ⋆ \star "处全部使用正号,也无法达到 n n n 的值。
所以我们便可以利用这个特性,让一个变量 t o t tot tot 每次累加 2 i 2^i 2i ,直到 t o t ≥ n tot\ge n totn,此时累加的次数就是答案。

CODE(这里提供三份代码):

def main():
	T = int(input())
	for k in range(T + 1):
		n = int(input())
		if not (n & 1):
			print(-1)
			continue
		tot = 0
		for i in range(0, 114514):
			tot += (1 << i)
			if tot >= n:
				print(i + 1)
#注意这里由于i从0开始,所以输出i+1
				break

if __name__ == '__main__':
	main()
#include <stdio.h>

int main() {
	int T, n, tot = 0;
	scanf("%d", &T);
	while(T --) {
		scanf("%d", &n);
		if(! (n & 1)) {
			printf("-1\n");
			continue;
		}
		for(int i = 0; ; i += 1) {
			tot += (1 << i);
			if(tot >= n) {
				printf("%d\n", i + 1);
				break;
			}
		}
		tot = 0;
	}
	return 0;
}
#include <bits/stdc++.h>

#define endl '\n'
  
using namespace std;

int T, n;
int tot = 0;

signed main() {
	
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	cin >> T;
	
	while(T --) {
		cin >> n;
		if(! (n & 1)) {
			cout << -1 << endl;
			continue;
		}
		for(int i = 0; ; i ++) {
			tot += (1 << i);
			if(tot >= n) {
				cout << i + 1 << endl;
				break;
			}
		}
		tot = 0;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值