暂时没有F题的题解。太菜了。
A - Collecting Coins
题意:有三个人,分别有a,b,c枚硬币,你有n枚硬币,要求把n枚硬币全部给这三个人并且使得他们的硬币数变为相等。问是否可行。
题解:先验证硬币总数a+b+c+n是否能被3整除,然后验证要补的硬币的数量少于n。
void test_case() {
int a[5], n;
scanf("%d%d%d%d", &a[1], &a[2], &a[3], &n);
sort(a + 1, a + 1 + 3);
int sum = a[3] - a[1] + a[3] - a[2];
if(sum > n || (sum - n) % 3 != 0)
puts("NO");
else
puts("YES");
}
B - Collecting Packages
题意:有个机器人,只能向上走或者向右走,要从(0,0)经过所有的点(xi,yi),求是否可行,若可行则输出字典序最小的方案。
题解:字典序最小就是说先往右走再往上走。直接把所有点按x排序,要求每个点与(0,0)包围的矩形包含此前的所有点,只需要比前面的点都高就行了。由数学归纳法可知只需要比前一个点高就行了。
int n;
pii p[1005];
void test_case() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
int x, y;
scanf("%d%d", &x, &y);
p[i] = {x, y};
}
sort(p + 1, p + 1 + n);
for(int i = 2; i <= n; ++i) {
if(p[i].second < p[i - 1].second) {
puts("NO");
return;
}
}
puts("YES");
int cx = 0, cy = 0;
for(int i = 1; i <= n; ++i) {
while(cx < p[i].first) {
putchar('R');
++cx;
}
while(cy < p[i].second) {
putchar('U');
++cy;
}
}
putchar('\n');
}
C - Product of Three Numbers
题意:给一个数n,满足n>=2,要求将n分解成互异的三个数a,b,c,使得a*b*c==n,且a,b,c>=2。给出一种分解的方案,或者说明其不存在。
题解:一开始没看见>=2直接判断质数就上了(虽然这样也不对,比如9不能分解为1,3,3),仔细一想跟质数的种类有关系,所以可以直接分解质因数。假如有3种以上的质因数,那么前两个数要两种,剩下的最后一个数补位就是一种字典序最小的构造。假如只有1种质因数,那么肯定至少需要6次,前两个数分别要1次和2次,剩下的至少要3次,这也是一种字典序最小的构造。假如有2种质因数,那么总次数<=3的显然是无解的,而总次数>=4的必定有解。首先把两种质因数各1次拿出来,那么剩下的那个2次也不会和前面的重复,只是这样并不是字典序最小(还好题目没要求)。
最简单的思路也是字典序最小的思路就是直接暴力枚举a和b。
下面这个质因数分解的模板貌似还带有筛出最小质因子的功能的。
const int MAXN = 1e5;
int p[MAXN + 5], ptop;
int pn[MAXN + 5];
void sieve() {
int n = MAXN;
pn[1] = 1;
for(int i = 2; i <= n; i++) {
if(!pn[i])
p[++ptop] = i;
for(int j = 1; j <= ptop; j++) {
int t = i * p[j];
if(t > n)
break;
pn[t] = p[j];
if(i % p[j] == 0)
break;
}
}
}
int fac[105][2], ftop;
void get_fac(int n) {
ftop = 0;
for(int i = 1; i <= ptop; ++i) {
if(n % p[i] == 0) {
fac[++ftop][0] = p[i];
fac[ftop][1] = 0;
while(n % p[i] == 0) {
n /= p[i];
++fac[ftop][1];
}
}
}
if(n > 1) {
fac[++ftop][0] = n;
fac[ftop][1] = 1;
}
}
void test_case() {
int n;
scanf("%d", &n);
get_fac(n);
if(ftop >= 3) {
puts("YES");
printf("%d %d %d\n", fac[1][0], fac[2][0], n / fac[1][0] / fac[2][0]);
return;
} else if(ftop == 1) {
if(fac[1][1] >= 6) {
puts("YES");
printf("%d %d %d\n", fac[1][0], fac[1][0]*fac[1][0], n / fac[1][0] / fac[1][0] / fac[1][0]);
return;
} else {
puts("NO");
return;
}
} else {
int sum = fac[1][1] + fac[2][1];
if(sum <= 3) {
puts("NO");
return;
} else {
puts("YES");
printf("%d %d %d\n", fac[1][0], fac[2][0], n / fac[1][0] / fac[2][0]);
return;
}
}
}
D - MEX maximizing
题意:有q次操作和一个固定的正整数x,每次操作会往序列中加入一个数字y,你可以在任何时候对序列中的某个y进行任意多次加减x操作(但不能使他们变成负数),求使得整个序列的MEX最大的方案时的MEX的值。
题解:显然模x余数相同的都是同一种等价的东西,可以维护模x值不同结果的cnt。那么MEX操作就相当于询问整个cnt序列中的最小值(这个最小值是一层一层循环叠在下面把MEX垫高),然后再求序列中等于这个最小值的最左边的元素,这个显然可以用线段树来维护(甚至可以支持修改删除)。
但是最简单的操作还是在cnt里面数了之后不断尝试越过MEX即可。
E - Obtain a Permutation
题意:给一个n*m的矩阵,要求复原成形如:
1 2 3 4
5 6 7 8
9 10 11 12
的样子,也就是依次填充。
有两种cost都是1的操作,1种是直接修改某位置的数字,另一种是把一列向上轮换。
原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12230102.html