暂时没有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