基础的选择题说实话不太行,基础不太扎实,然后编程题倒是不太难,这边写一下题解。
第一题
题意
大概是给你一个n,然后找一对a,b满足a,b都小于n。并且lcm(a,b)-gcd(a,b)最小。
分析
一开始以为和一道做过的cf题一样,仔细想了下发现更简单,这个就是要lcm最大同时gcd最小,gcd最小一定是1,同时使得lcm最大,那一定是n和n-1。于是答案就是n*(n-1)-1
,注意要开longlong。
我的代码
#include <iostream>
typedef long long ll;
using namespace std;
ll n, ans;
int main() {
while( cin >> n ) {
ans = n * (n-1) - 1;
cout << ans << endl;
}
return 0;
}
第二题
题意
两个人轮流取n组石头,每次取每组里面的其中1个,当取的人取的时候每一组都没有剩余石头即都是0,或者取完后有两组石头相同的时候就输。问最后谁赢。
分析
一开始以为是一个常规的博弈,后来发现题目看错了。这个题目也是思维题,可以模拟一下取石头,可以发现当石头取成形如(0, 1, 2, 3, 4…)时,下一个人必输。于是我们可以计算需要几步可以取成如下情形,那么此时下一个人必输。不过不要忘记一些特殊情况,一开始就有3组以上相同(如2, 2, 2),一开始就有两个以上相同的两组(如4, 4, 5, 5),还有全是0的。
我的代码
#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
int T, n;
int a[100005];
int sum;
int main() {
scanf("%d",&T);
while(T--) {
map<int, int> M;
int flag2 = 0, flag3 = 0;
scanf("%d",&n); sum = 0;
for (int i=1; i<=n; ++i) {
scanf("%d",&a[i]);
sum+=a[i];
M[a[i]]++;
if ( M[a[i]] == 2 ) flag2++;
if ( M[a[i]] == 3 ) flag3++;
}
if ( flag3 ) printf("woman\n");
else if ( flag2 >= 2 ) printf("woman\n");
else if ( (sum-n*(n-1)/2) % 2 == 0 ) printf("woman\n");
else printf("man\n");
}
return 0;
}
第三题
题意
有一个飞船从n*m大小的矩形的左侧飞到右侧,然后中间有很多点,求离所有点包括上下边界的距离的最小值的最大值。其实就是求你这条路径到离得最近的点(或者上下边界)的距离,使得这个距离最大。
分析
初步考虑二分距离,然后判断该距离是否可行。判断的话就是把每个点看作一个圆,圆的内部是不能走的,看一下这些圆会不会堵住上下边界。因为给的点的个数为k个,k最大6000,这个复杂度的话直接暴力判断是不行的。于是我的想法是用并查集合并有交集的点,如果这些有交集的点能覆盖整个上下边界,那么就说明是不存在路的。这样复杂度就变成了60006000二分次数。其实这样的时间复杂度有点玄的,一开始也确实只过了一半,然后不断调整参数,优化,最后终于调到了100%。
我的代码
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define MAXN 6005
double up, down;
int n, m, k;
double x[MAXN], y[MAXN];
int fa[MAXN];
int u[MAXN], d[MAXN];
double dist[MAXN][MAXN];
inline
void init() {
for ( int i=0; i<=k; ++i )
fa[i]=i;
}
inline
int find(int x) {
if ( fa[x] == x ) return x;
return fa[x] = find( fa[x] );
}
inline
void combine( int x, int y ) {
int fx = find(x), fy = find(y);
if ( fx == fy ) return;
fa[fy] = fx;
}
inline
double dis( int i, int j ) {
return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
bool judge( double x ) {
init();
for ( int i = 1; i <= k; ++i ) {
u[i] = d[i] = 0;
for ( int j = i+1; j <= k; ++j ) {
if ( dist[i][j] <= 2 * x )
combine(i, j);
}
}
for ( int i = 1; i <= k; ++i ) {
int f = find(i);
if ( y[i] + x > up ) u[f] = 1;
if ( y[i] - x < down ) d[f] = 1;
if ( u[f] && d[f] ) return false;
}
return true;
}
int main() {
scanf("%d%d%d",&n, &m, &k);
for ( int i=1; i<=k; ++i ) {
scanf("%lf%lf", &x[i], &y[i]);
}
for ( int i = 1; i <= k; ++i ) {
u[i] = d[i] = 0;
for ( int j = i+1; j <= k; ++j ) {
dist[i][j] = dis(i,j);
}
}
double l=0, r=5e5, mid;
for ( int i=1; i<=45; ++i )
{
mid = (l+r) / 2.0;
up = m - mid;
down = mid;
if ( judge(mid) ) {
l = mid;
} else {
r = mid;
}
}
printf("%.4lf\n",mid);
return 0;
}