奇怪的电梯(贪心,思维)
题意
一共有 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 1≤n≤1018, 0≤k≤1018, 1≤a,b≤n
思路
这个题想了很久,很多思路都没考虑完全,导致 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 2≤n≤1×106, 1≤ai≤106
思路
一开始看到这道题的时候,根据以往做 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;
}
最大公约数,真就是纯粹的找出最大的那个公约数,确实没想到。
之前做的都是通过质数来求,思维太固化了!