2021年ACM竞赛班训练(三)

1|02021年ACM竞赛班训练(三)

1|1A题 验证哥德巴赫猜想

请移步验证哥德巴赫猜想

1|2B题 路径

请移步路径

1|3C题 组合数

原题链接

1|0思路

  1. 预处理组合数:
    mn的范围均在2000以内, 可以采用O(N2)的算法预处理所有的组合数.
    求解组合数的几种算法详见组合数
  2. 预处理二维前缀和:
    由于多组测试数据, 仅仅预处理出组合数是不够的, 必须预处理所有的结果, 这样对于每次询问都达到O(1)
    运用动态规划的思想(也可以理解为二维前缀和):

1|0状态表示:

dp[i][j]: C0i0j中满足整除k的集合
属性: 数量

1|0状态计算:

dp[i1][j]: C0(i1)0j中满足整除k的集合
dp[i][j1]: C0i0(j1)中满足整除k的集合
以上两部分有重合:
dp[i1][j1]: C0(i1)0(j1)中满足整除k的集合
得到递推式:

dp[i][j]=dp[i1][j]+dp[i][j1]dp[i1][j1]

1|0代码

#include <iostream> #include <cstring> using namespace std; const int N = 2010; int t, k; int c[N][N]; int res[N][N]; void init() { for (int i = 0; i < N; i ++ ){ for (int j = 0; j <= i; j ++ ) if (j == 0) c[i][j] = 1; else{ c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % k; res[i][j] = res[i - 1][j] + res[i][j - 1] - res[i - 1][j - 1]; if (c[i][j] == 0) res[i][j]++; } res[i][i + 1] = res[i][i]; //向下一层传递当前总数 } } void solve() { int n, m; scanf("%d%d", &n, &m); m = min(m, n); cout << res[n][m] << endl; return; } int main() { cin >> t >> k; init(); while (t -- ) solve(); return 0; }

1|4E题 a math problem(hard version)

原题链接

1|0思路:

l,r范围均在11e18, 暴力枚举肯定会超时.
应用容斥原理(原理详见:容斥原理)
对于每个数x, 我们对其分解质因数, 分解得到p1,p2...pm, 共计m个质因数, 问题转化为:
lr的所有数中, 有多少数能够至少被这m个质数中的一个整除.(详见容斥原理中的例题)

那么解决该问题只需两步即可:

  1. x分解质因数
  2. 分别对区间[1,l1][1,r]应用容斥原理, 结果相减即可.

1|0代码

#include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long LL; // 容斥原理 long long s[100010]; int n = 0; void divide(LL x) { for (int i = 2; i <= x / i; i ++ ) if (x % i == 0){ s[n ++] = i; while (x % i == 0) x = x / i; } if (x > 1) s[n ++] = x; return; } LL solve(LL m) { LL ans = 0; for (int i = 1; i < 1 << n; i ++ ){ LL t = 1; //当前二进制所表示的所有集合内的数字的质数之积 int cnt = 0; //当前二进制表示的集合个数 for (int j = 0; j < n; j ++ ){ //枚举当前二进制的每一位 if (i >> j & 1){ if (t * s[j] > m){ //当前集合内的数 t = -1; break; } cnt++; t = t * s[j]; } } if (t != -1){ if (cnt % 2) ans += m / t; else ans -= m / t; } } return m - ans; } int main() { long long l, r, x; cin >> l >> r >> x; divide(x); //分解质因数 cout << solve(r) - solve(l - 1) << endl; return 0; }

1|0为什么这样做不会超时:

25以内的质数(9个):
2 3 5 7 11 13 17 19 23
它们的乘积:223092870>2e9
即对于任意的 x<2e9 :不会超过9个不同的质因子
即:应用容斥原理时最多有9个集合,总共需要枚举的集合的组合方式有29
对于每种组合方式, 我们枚举二进制的每一位时, 最多有9
即时间复杂度大概在2×9×29

1|5F题: 矩阵变换

原题链接

1|0思路

题目数据范围不大, 直接根据题意模拟即可

1|0代码

#include <iostream> #include <cstring> #include <string> using namespace std; const int N = 510; int n, m, k; char s[N][N]; int a, b, c, d; int op; void turnup() { if ((c + d) % 2 == 0){ int t = (c + d) / 2; for (int i = a; i <= b; i ++ ){ for (int j = c; j < t; j ++ ){ char cs = s[i][j]; s[i][j] = s[i][2 * t - j]; s[i][2 * t - j] = cs; } } }else{ int t = (c + d) / 2; for (int i = a; i <= b; i ++ ) for (int j = c; j <= t; j ++ ){ char cs = s[i][j]; s[i][j] = s[i][2 * t + 1 - j]; s[i][2 * t + 1 - j] = cs; } } } void turndown() { if ((a + b) % 2 == 0){ int t = (a + b) / 2; for (int i = c; i <= d; i ++ ){ for (int j = a; j < t; j ++ ){ char cs = s[j][i]; s[j][i] = s[2 * t - j][i]; s[2 * t - j][i] = cs; } } }else{ int t = (a + b) / 2; for (int i = c; i <= d; i ++ ) for (int j = a; j <= t; j ++ ){ char cs = s[j][i]; s[j][i] = s[2 * t + 1 - j][i]; s[2 * t + 1 - j][i] = cs; } } } void solve() { cin >> op >> a >> b >> c >> d; if (op == 1){ turnup(); }else{ turndown(); } for (int i = 1; i <= n; i ++ ){ cout << s[i] + 1; puts(""); } puts(""); return; } int main() { cin >> n >> m >> k; for (int i = 1; i <= n; i ++ ) cin >> s[i] + 1; while (k--) solve(); return 0; }

__EOF__

本文作者lhqwd
本文链接https://www.cnblogs.com/lhqwd/p/14637530.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   lhqwd  阅读(156)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示