https://ac.nowcoder.com/acm/contest/10743
A
思维题。
最终的gcd最大值必为排序后每两个相邻数的差值的gcd。
那么就计算最小的数需要加多少才能成为这个gcd的倍数就可以了。
#include <bits/stdc++.h> #define sc(x) scanf("%lld", &(x)) #define pr(x) printf("%lld\n", (x)) using namespace std; typedef long long ll; const int N = 1e5 + 7; const int mod = 1e9 + 7; ll a[N], d[N]; int main() { ll n; sc(n); for (int i = 1; i <= n; ++i) sc(a[i]); sort(a + 1, a + 1 + n); for (int i = 1; i < n; ++i) d[i] = a[i + 1] - a[i]; ll ans = d[1]; for (int i = 2; i < n; ++i) ans = __gcd(ans, d[i]); if (ans == 1) puts("1 0"); else cout << ans<<' ' << ans - a[1] % ans; return 0; }
B
是k-gcd的变形,说是埃筛也没什么问题。无论选多少个数,答案必然在之间,那么就可以枚举每个因数,通过桶来看有多少个数是它的倍数。
从大到小枚举就是最优的枚举方案,所以只有没有访问过的才会记录。
最后覆盖一遍答案就可以了,因为如果有个数都是的倍数,那么必然也可以选出来个数,使其满足是的倍数。
#include <stdio.h> const int maxn = 1e5 + 7; int a[maxn], ans[maxn]; int main() { int n, x; scanf("%d", &n); int maxa = 0; for (int i = 0; i < n; ++i) { scanf("%d", &x), ++a[x]; if (x > maxa) maxa = x; } for (int i = maxa; i; --i) { int cnt = 0; //有cnt个数是i的倍数 for (int j = i; j <= maxa; j += i) cnt += a[j]; if (!ans[cnt]) ans[cnt] = i; } for (int i = n; i > 1; --i) { if (ans[i + 1] > ans[i]) ans[i] = ans[i + 1]; } for (int i = 2; i <= n; ++i) printf("%d ", ans[i]); return 0; }
C
其实就是Floyd,但是可能会T(虽然数据水并没有),但是题目只要求是否可达,所以此处可用bitset优化。
具体来说是建两张图:
- 一定能到图:收纳所有一定存在的边
- 可能能到图:只要不是一定不存在的边,都收纳进去
#include <bits/stdc++.h> using namespace std; int n, m1, m2, q, x, y; const int maxn = 1005; bitset<maxn> f[maxn], g[maxn]; int main() { scanf("%d%d%d%d", &n, &m1, &m2, &q); for (int i = 1; i <= n; i++) { f[i].reset(); //初始化为0 g[i].set(); //初始化为1 f[i][i] = 1; //自己必定可达自己 } for (int i = 1; i <= m1; ++i) scanf("%d%d", &x, &y), f[x][y] = 1; for (int i = 1; i <= m2; ++i) scanf("%d%d", &x, &y), g[x][y] = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { if (f[j][i]) f[j] |= f[i]; if (g[j][i]) g[j] |= g[i]; } while (q--) { scanf("%d%d", &x, &y); printf(f[x][y] ? "Yes " : "No "); puts(g[x][y] ? "Yes" : "No"); } return 0; }