比赛入口
B. Omkar and Last Class of Math
题意:给出一个整数 n n n(1e9范围内),给出条件 a + b = n a+b=n a+b=n,要使得 l c m ( a , b ) lcm(a,b) lcm(a,b)最小,输出 a a a和 b b b。
做法:结论是其中一个答案是
n
n
n的最大因子(由于不会证明被拖出去枪毙 ),找了找官方题解的证明,总结(翻译 )了一下证明如下:
令
a
=
k
,
b
=
n
−
k
a=k,b=n-k
a=k,b=n−k,假设
k
≤
n
−
k
k≤n-k
k≤n−k,意味着
n
−
k
≥
n
2
n-k≥ \frac{n}{2}
n−k≥2n;
如果
k
∣
n
k|n
k∣n,即存在
m
∗
k
=
n
,
n
−
k
=
m
∗
k
−
k
=
(
m
−
1
)
∗
k
m*k=n,n-k=m*k-k=(m-1)*k
m∗k=n,n−k=m∗k−k=(m−1)∗k,这时可得
l
c
m
(
k
,
n
−
k
)
=
n
−
k
<
n
lcm(k, n-k)=n-k<n
lcm(k,n−k)=n−k<n;
如果
k
†
n
k\dagger n
k†n,且
k
†
n
−
k
k\dagger n-k
k†n−k,那么
l
c
m
(
k
,
n
−
k
)
≠
n
−
k
lcm(k,n-k) \ne n-k
lcm(k,n−k)=n−k,且
l
c
m
(
k
,
n
−
k
)
lcm(k, n-k)
lcm(k,n−k)会是
k
k
k和
n
−
k
n-k
n−k的乘积,这时
l
c
m
(
k
,
n
−
k
)
≥
2
∗
(
n
−
k
)
≥
2
∗
n
2
=
n
lcm(k,n-k)≥2*(n-k)≥2*\frac{n}{2} = n
lcm(k,n−k)≥2∗(n−k)≥2∗2n=n;
k
∣
n
k|n
k∣n时
l
c
m
<
n
lcm<n
lcm<n,而
k
†
n
k\dagger n
k†n时
l
c
m
≥
n
lcm≥n
lcm≥n,故
k
∣
n
k|n
k∣n时
l
c
m
lcm
lcm存在最小,且当
k
∣
n
k|n
k∣n时,因为答案
l
c
m
(
k
,
n
−
k
)
=
n
−
k
lcm(k,n-k)=n-k
lcm(k,n−k)=n−k,要使得
n
−
k
n-k
n−k尽量小,那么
k
k
k就得尽量大,故
k
k
k就是
n
n
n的最大因子啦。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL res = 1e18;
int main() {
int t; scanf("%d", &t);
int n;
while(t--) {
scanf("%d", &n);
int a, b, ans = n - 1;
for(int i = 1; i*i <= n; ++i) {
if(n % i == 0) {
ans = min(ans, n-i);
if(i != 1) ans = min(ans, n-n/i);
}
}
printf("%d %d\n", ans, n-ans);
}
return 0;
}
C. Omkar and Baseball
题意:有一种操作,会使得一个区间内所有数字位置都和原来位置不同,问最少多少次操作能使得长度为 n n n(2e5范围内)的全排列变为 1 − n 1-n 1−n的顺序排列。
做法:一共是三种情况:
首先排除首尾已经在本位上的数字。
1、对于已经排好序的排列结果就是
0
0
0
2、对于完全打乱的排列只需要
1
1
1次操作就能恢复顺序排列。
3、对于部分打乱的排列结果是
2
2
2,第一次让所有位置的都打乱,使得部分打乱的数字能回到原位,第二次还原原本就在本位上的数字,一共两次。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+10;
int a[N];
int main() {
int t; scanf("%d", &t);
int n;
while(t--) {
deque<int> dq;
scanf("%d", &n);
for(int i = 1, x; i <= n; ++i) {
scanf("%d", &x);
a[i] = 0; if(x == i) a[i] = 1;
}
//排除首位已经排好序的
int lo = 1, hi = n;
while(lo <= hi && a[lo]) ++lo;
while(lo <= hi && a[hi]) --hi;
if(lo > hi) {
puts("0"); continue;
}
int res = 0;
for(int i = lo; i <= hi; ++i) {
if(!a[i]) ++res;
}
if(res == hi-lo+1) puts("1");
else if(res) puts("2");
}
return 0;
}
D. Omkar and Circle
题意:有 n n n(2e5范围内且一定是奇数)个数字组成一个环,可以采用的操作是选取一个数字,用与他相邻的两个数字的和代替他自己,然后删掉相邻的两个数字,重复该操作,直到最后只剩下一个数字,要使得该数字最大,输出该数字。
做法:写出一组数据然后枚举情况就能发现,有固定的间隙的一些数字成为一个组合,这些数字的和是必须加上的,只是间隙所在位置不一样,直接暴力枚举就好啦!
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=4e5+10;
LL a[N],sum[N];
int main(){
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
a[i+n] = a[i];
}
sum[1] = a[1];
for(int i = 2; i <= n*2; i++) sum[i] = sum[i-2] + a[i];
LL ans = 0;
for(int i = n+1; i <= n*2; i++) ans = max(ans, sum[i]-sum[i-n-1]);
printf("%lld\n", ans);
return 0;
}