CSP模拟-8
今天T1终于看懂辣。。。。但今天名次最低QAQ。T1没算空间复杂度,直接炸QAQ
T1 Coprime 2
今天T1确实简单,将输入的数的质数公因数用埃氏筛筛出来,用一个数组存下来。每次将质因数的倍数用
正确性的话:一个合数因数一定会被分解成一个或多个质因数,所以每次找质因数就行辣。(我相信你们都明白吧QAQ)
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <vector> using namespace std; int n, a[5211314], m; int gcd_sum, ans[2000010], sum, is_gcd[2000010], rec_gcd[2000010]; bool barrel[2000010], is_prime[2000010], flag[2000010]; void Prime() { //正经的埃氏筛 memset(is_prime, true, sizeof(is_prime)); for (int i = 2; i <= m; ++ i) { if (is_prime[i] == false) continue; for (int j = i; j <= m; j = j + i) { is_prime[j] = false; //找输入的数的质因数 if (barrel[j] == true && rec_gcd[i] == false) { //如果i的倍数是输入的数并且质因数i没有被存过 is_gcd[++ gcd_sum] = i; rec_gcd[i] = true; //这里记录的原因是保证复杂度 } } } return; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++ i) { scanf("%d", &a[i]); barrel[a[i]] = true; //将输入的数用桶先存下来 } Prime(); for (int i = 1; i <= gcd_sum; ++ i) { for (int j = is_gcd[i]; j <= m; j += is_gcd[i]) { //将每个质数因数的倍数标记 flag[j] = true; } } for (int i = 1; i <= m; ++ i) { if (flag[i] == false) { //不存在输入的数的质因数 ans[++ sum] = i; } } //输出 printf("%d\n", sum); for (int i = 1; i <= sum; ++ i) { printf("%d\n", ans[i]); } return 0; }
T2 Dist Max 2
又是逆天二分QAQ,永远写不对的边界条件,我真服了。
看见找最小值的最大值,一眼丁真鉴定为二分答案。
设我们现在已经枚举到
此时我们直接遇事不决先排序,将点以
我们的双指针
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; int n; struct Picture { int x, y; bool operator < (const Picture & b) const { if (x != b.x) return x < b.x; return y < b.y; }//sort的时候用 }a[1000100]; bool check(int differ) { int MaxY = -1e9, MinY = 1e9; //在l之前Y轴的最值 for (int r = 1, l = 0; r <= n; ++ r) { //这里面的l表示左半部分的右端点,r表示右半部分的左端点 //l就是左指针,r就是右指针 while (l < r && a[r].x - a[l + 1].x >= differ) { //若存在更小的X轴之差符合差最小值得differ的条件,就更新l的值 MaxY = max(MaxY, a[l + 1].y); MinY = min(MinY, a[l + 1].y); //将左指针新包含的范围内的MaxY和MinY更新 l ++; } if (MaxY - a[r].y >= differ) return true; if (a[r].y - MinY >= differ) return true; //判断左边的Y的最值与右侧的Y的最值的差是不是大于differ //在循环里我们相当于将右指针后面的数全部枚举了一遍最大值,最小值 //左指针除了l=r=1的时候处理右指针,其他时候都是左指针跟着右指针移动 //所以在右指针更新的时候,左指针左边的MaxY与MinY也都被更新了,正确性可以保证 } return false; } int main() { scanf("%d", &n); for (int i = 1; i <= n; ++ i) { scanf("%d%d", &a[i].x, &a[i].y); } sort(a + 1, a + 1 + n); int l = 0, r = 1e9, ans = 0; while (l <= r) { //二分找最值 int mid = (l + r) >> 1; if (check(mid)) { l = mid + 1; ans = mid; } else r = mid - 1; } printf("%d\n", ans); return 0; }
PS:顺带附上找最最大的最小值
while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) { r = mid - 1; ans = mid; } else l = mid + 1; }
T3 [ABC221H] Count Multiset
这边建议[这篇题解](「解题报告」[ABC221H] Count Multiset - K8He - 洛谷博客 (luogu.com.cn))。写的很好,复杂度优。
#include <iostream> #include <cmath> #include <algorithm> #include <cstring> #include <cstdio> #define mod 998244353 using namespace std; typedef long long ll; int n, m, f[5210][5210], g[5210][5210], sum[5210][5210]; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++ i) { if (i <= m) f[i][0] = 1; for (int j = 1; j <= n; ++ j) { if (j >= i) f[i][j] = g[i][j] = f[i][j - i]; sum[i][j] = (sum[i - 1][j] + g[i][j]) % mod; f[i][j] = ((f[i][j] + sum[i - 1][j]) % mod - sum[max(0, i - m - 1)][j] + mod) % mod; } } for (int i = 1; i <= n; ++ i) { cout << g[i][n] << endl; } return 0; }
T4 Julia the snail
数据加强版,吉司机线段树不会,咕。
总结
本次考试分数最高,但名词最低QAQ。T1直接炸,没考虑空间复杂度,下一次不能再犯辣。T2没看见是整数,不敢开
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律