codeforces Good Bye 2022
A. Koxia and Whiteboards
题解
根据提意,每次对a数组最小元素的操作就好了,因为n,m的范围比较小,所以没必要用优先对列。
#include<bits/stdc++.h>
using namespace std;
#define in(n) cin>>n;
#define out(m) cout<<m;
const int maxn = 1e2 + 5;
int a[maxn],b[maxn];
int min(int x, int y)
{
if (x < y)return x;
return y;
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 1; i <= m; i++)cin >> b[i];
sort(a + 1, a + 1 + n);
for (int i = 1; i <=m; i++)
{
a[1] = b[i];
sort(a + 1, a + 1 + n);//每次操作后排序一下保证a[1]始终最小
}
long long sum=0;//计算结果要开long long 因为结果肯定会超过int
for (int i = 1; i <= n; i++)sum += a[i];
printf("%lld\n", sum);
}
return 0;
}
B. Koxia and Permutation
题解
翻译一下题目就是找到长度为n的数组,并且这个数组中所有长度为k连续的一部分的最大值最小值之和又组成了一个数组c,要求c中的最大值尽量小。
举个例子
如果p[10]={1,2,3,4,5,6,7,8,9};
那么
c1=max{1,2,3}+min{1,2,3}
c2=max{2,3,4}+min{2,3,4}
.....
c8=max{8,9,10}+min{8,9,10}
理解了题意,现在就考虑怎么找这个数组,首先题中说到了p中的元素不能重复,那么很容易就可以想到用 1,2,3,4,5,6,7,8,9,10......n 这些是我们知道的最小的正整数,现在的的问题就是如何排列这些数。我们要优先考虑最大的数 n 应该放哪里,并且我们不希望它接触太多的数,所以我们选择将n放到边上,这里我们将它放到最左边,也就是第一组的最左边,然后再把最小的数 1 安排到它附近让值尽量更小,并且我们希望 1 可以接触尽量多的数,所以放在第一组的最右边,同理我们在第一组可以放尽量大的数因为第一组的最大值和最小值都确定了,并且同理大的要靠左,同理我们对接下来没放数的位置进行操作。
这里还是以 10 3 为例,每两个空格之间代表需要填一个数
,10,9,1,8,7,6,2,5,4,3,
代码实现的步骤如下
第一步:10,9, ,8,7, ,6,5, ,4, 把序号为k的倍数的位置先空开 第二步:10,9,1,8,7,2,6,5,3,4,把空位按从小到大的顺序填上
#include<bits/stdc++.h>
using namespace std;
int a[200005];
int main()
{
int t;
cin >> t;
while (t--)
{
int n, k;
cin >> n >> k;
int count = n;
int flag = 1;
for (int i = 1; i <= n; i++)
{
if (i % k)a[i] = count--;
}
int count2 = 1;
for (int i = k; i <= n; i += k)
{
a[i] = count2++;
}
for (int i = 1; i <= n; i++)printf("%d ", a[i]);
printf("\n");
}
return 0;
}
C. Koxia and Number Theory
题解
题意很容易理解,给一组数a,问有没有x使得a中每一个元素加上x后两两互质。
看到这题首先会想到枚举,但是看到这个数据范围就知道枚举模拟行不通,这时候就应该考虑互质、公因数的一些性质。怎样会无论加什么数都不能让a中的元素互质。
首先容易考虑的就是数组中含有相同的元素。如果含有相同的元素直接输出NO
然后就要考虑元素不同怎么办。我们需要从例子中寻找规律,比如,2 4 5 7,我们观察发现这组数是NO,因为你无论加的是奇数还是偶数,都会出现两个偶数。然后扩大一下例子的长度1 3 5 7 9 11,表面上我们很难判断是YES还是NO,我们从上一个例子拓展一下,上个例子为什么会出现这种现象,2 4 5 7 中含有两个偶数,两个奇数,奇数加奇数是偶数,偶数加偶数是偶数,我们能不能吧这个拓展出奇数偶数的范围呢。如果x=1,结合膜的性质,数组变为3 5 6 7这个奇数偶数的变化过程可以被看做(2%2 + x%2)%2 = 1,所以是奇数,(4%2 + x%2)%2 = 1,所以是奇数,(5%2 + 1%2)%2 = 0,所以是偶数,(7%2 + 1%2)%2 = 0,所以是偶数。找到规律要和元素互补就会出现公约数,比如,4 7,这两个数模3都是1,如果给他们加上2,,5,8,11等值为(3*k+2)的数因为相当于4 7和这些数“互补”,补为某个数的倍数,回到1 3 5 7 9 11显然不是所有数都会让1 3 5 7 9 11中的两个及以上数变成2的倍数,那么我们考虑可不可能成为3的倍数,先对这些数取模得到1 0 2 1 0 2,这样就显而易见了,无论我们选任何数都会让其中两个数变成3的倍数。那么4的倍数或5的倍数呢,这些显然不可能,因为数字个数只有6个,无法涵盖a%4出现的所有情况的两倍,会有漏洞,我们将这组数对4取模得到 1 3 1 3 1 3,0 和2没有涵盖到,所以我们枚举时只要枚举小于等于n/2的倍数。
再对1 3 5 7 9 11进行分析,6个数,只需要枚举倍数[2,3]的情况,当倍数为2时,取模得1 1 1 1 1 1,没有涵盖所有情况,当倍数为3时 ,取模得 1 0 2 1 0 2,涵盖了所有情况,无论取什么数都会有两个数变成3的倍数。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e2 + 5;
long long a[maxn];
int b[105];
int main()
{
int t;
cin >> t;
while (t--)
{
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
int n;
cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
sort(a + 1, a + 1 + n);
int flag0 = 0;
for (int i = 2; i <= n; i++)
{
if (a[i] == a[i - 1])
{
printf("NO\n");
flag0 = 1;
break;
}
}
if (flag0)continue;
int flag = 1;
int count=1;
for (int x = 2; x <= n/2 ; x++)
{
flag = 1;
for (int i = 1; i <= n; i++)
{
int c = a[i] % x;
b[c]++;
}
for (int i = 0; i <= x - 1; i++)
{
if (b[i] < 2)
{
flag = 0;
}
}
memset(b, 0, sizeof b);
if (flag)
{
count = 0;
break;
}
}
if (count)printf("YES\n");
else printf("NO\n");
}
return 0;
}