明月计划第 1 弹 - 牛客月赛57

奇怪的电梯(贪心,思维)

题意
一共有 n 层, 每一层有电梯。
但是进入电梯的时候相邻的 k 层不能按,
假设你在 x 层进入了电梯,那么 x - k 到 x + k 层之间的所有楼层都去不了。

现在给出 n,k,a,b,判断能否可以从 a 层到达 b 层?(中途可以换乘)

1 ≤ n ≤ 1 0 18 ,   0 ≤ k ≤ 1 0 18 ,   1 ≤ a , b ≤ n 1≤n≤10^{18},\ 0≤k≤10^{18}, \ 1≤a,b≤n 1n1018, 0k1018, 1a,bn

思路
这个题想了很久,很多思路都没考虑完全,导致 wa 了很多次。

从一个点出发,不能走到相邻的 2k 个位置,但是如果能走到一个位置的话,除了那个位置相邻的 2k 个位置之外,其余所有位置都能到达。

能够从起点走到并且能够到达的位置尽可能多,贪心地先走到 1 位置或者 n 位置:

  • 如果起点能到达 1 位置的话,那么 [1+k+1, n] 中的所有点都可达,既然能走到 n,那么 [1, n-k-1] 中的所有点又可达;
  • 如果能到达 n 位置的话,那么 [1, n-k-1] 中的所有点都可达。既然能走到 1,那么 [1+k+1, n] 中的所有点又可达。

如果这两个位置都不能走到的话,那么肯定就说明所有层除了起点都不可达。

特判终点在起点的情况。

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

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];

signed main(){  
	Ios;
	cin >> T;
	while(T--)
	{
		int k, a, b;
		cin >> n >> k >> a >> b;
		if(a + k < n && (b <= n - k - 1 || b >= 1 + k + 1)) cout << "YES\n";
		else if(a - k > 1 && (b >= 1 + k + 1 || b <= n - k - 1)) cout << "YES\n";
		else if(a == b) cout << "YES\n";
		else cout << "NO\n";
	}
	
	return 0;
}

最大gcd(gcd)

题意
给出一个长度为 n 的数列。
选择两个位置上的数求 gcd,问 gcd 最大能为多少?

2 ≤ n ≤ 1 × 1 0 6 ,   1 ≤ a i ≤ 1 0 6 2≤n≤1×10^6,\ 1≤a_i ≤10^6 2n1×106, 1ai106

思路
一开始看到这道题的时候,根据以往做 gcd 类型题目的经验,肯定和质数相关,然后就想着先分解质因数,1e6大小正好,但是分解完之后呢?要选择两个数使得 gcd 最大,而两个数中质因数有好几种,要保证乘积最大,如何选择呢?就不好搞了。

正解其实很简单,就是考察了 gcd 的最原始的性质。
最大公约数,肯定是两个数的约数,那么这两个数就一定是其倍数。
此外,两个数的最大公约数大小一定不会超过两者

而所有数的大小都在 1e6,那么就可以枚举 1-1e6 所有数作为公约数,然后再验证数列中是否存在两个数的公约数是这个数。

如何验证呢?
遍历其所有倍数,看是否在数列中出现过至少两次。

取所有满足的公约数的最大值,便是满足的最大公约数

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

#define Ios ios::sync_with_stdio(false),cin.tie(0)

const int N = 2000010, mod = 1e9+7;
int T, n, m;
int a[N], mp[N];

signed main(){
	scanf("%d", &n);
	
	int maxa = 0;
	for(int i=1;i<=n;i++){
		scanf("%d", &a[i]);
		mp[a[i]] ++;
		maxa = max(maxa, a[i]);
	}
	
	int ans = 1;
	for(int i=2;i<=maxa;i++)
	{
		int cnt = 0;
		for(int j=i;j<=maxa;j+=i) cnt += mp[j];
		if(cnt >= 2) ans = max(ans, i);
	}
	cout << ans;
	
	return 0;
}

最大公约数,真就是纯粹的找出最大的那个公约数,确实没想到。
之前做的都是通过质数来求,思维太固化了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值