牛客练习赛128补题
A. Cidoai的幂次序列
思路
思维题
题面看着复杂,但只需输出 \(n-1\) 和 \(1\) 即可。
代码
#include <iostream> using namespace std; typedef long long ll; ll n, k; int main() { cin >> n >> k; cout << 2 << '\n'; cout << n - 1 << ' ' << 1; return 0; }
B. Cidoai的平均数对
思路
01背包
根据题意有
将 \(n\) 移到右边
再将 \(n * k\) 移到左边
将 \(k\) 放入 \(b_i\) 求和的式子中
所以要满足最终和小于等于0,可以将所有\(b_i-k\),显然结果为负数的一定可选,结果为正数的可选可不选,这样就转为一个典型的01背包问题,我先将结果为负的都选上求和为背包容量,结果为正的作为体积,对应的\(a_i\)为价值。
代码
#include <iostream> using namespace std; const int N = 500 + 10, M = N * N; int n, k, sum; int a[N], b[N]; int dp[M]; int main() { cin >> n >> k; for (int i = 1; i <= n; i ++) { cin >> a[i] >> b[i]; b[i] -= k; if (b[i] < 0) { sum -= b[i]; b[i] = 0; } } for (int i = 1; i <= n; i ++) for (int j = sum; j >= b[i]; j --) dp[j] = max(dp[j], dp[j - b[i]] + a[i]); cout << dp[sum]; return 0; }
C. Cidoai的树上方案
思路
树形dp模板
简单图就是不含自环和重边的图。
树外一个点连接树内任意点,求不构成三元环的方案数。可以知道构成三元环,除树外的点与树内两个点相连,还有一个条件是树内两个点要相连,即相邻的两个点,由此题目转为,找不相邻的任意个点的方案数,就是一个树形dp的模板了。
代码
#include <iostream> #include <vector> using namespace std; typedef long long ll; const int mod = 998244353; const int N = 2e6 + 10; int n; vector<int> g[N]; ll dp[N][2]; void dfs(int u) { dp[u][0] = dp[u][1] = 1; for (int v : g[u]) { dfs(v); dp[u][0] = dp[u][0] * (dp[v][0] + dp[v][1]) % mod; dp[u][1] = dp[u][1] * dp[v][0] % mod; } } int main() { cin >> n; for (int i = 2; i <= n; i ++) { int x; cin >> x; g[x].push_back(i); } dfs(1); cout << (dp[1][0] + dp[1][1]) % mod; return 0; }
D. Cidoai的字符集合
思路
并查集模板
题目是求两个分类的总和,一个是有歌曲是相似的集合数1加上独立歌曲的数量n。
用map记录一下每个旋律对应哪首歌,快速判断这首歌是不是可能相似了,再用并查集找出相似的两首歌,将相似的两首歌放入集合0中。最后枚举一下0~n首歌,它父节点是它本身的数量就是答案。
代码
#include <iostream> #include <unordered_map> using namespace std; const int N = 1e6 + 10; int n; unordered_map<string, int> mp; int p[N]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int main() { cin >> n; for (int i = 1; i <= n; i ++) p[i] = i; for (int i = 1; i <= n; i ++) { int k; cin >> k; while (k --) { string s; cin >> s; if (mp.count(s)) { int pi = find(i), ps = find(mp[s]); if (pi == ps) continue; p[pi] = 0; p[ps] = 0; } else mp[s] = i; } } int res = 0; for (int i = 0; i <= n; i ++) if (p[i] == i) res ++; cout << res; return 0; }
E. Cidoai的映射数列
矩阵快速幂优化状态压缩,听牛客官方补的题。
代码
#include <iostream> #include <cstring> using namespace std; typedef long long ll; const int N = 128; const int mod = 998244353; struct Matrix { int n, m; ll mat[N][N]; Matrix() {} Matrix(int _n, int _m): n(_n), m(_m) {} Matrix(int _n, int _m, bool flag) : n(_n), m(_m) { memset(mat, 0, sizeof mat); if (flag) for (int i = 0; i < n; i ++) mat[i][i] = 1; } Matrix(int k) { n = m = 1 << k; memset(mat, 0, sizeof mat); for (int st = 0; st < n; st ++) { mat[st][st >> 1] = 1; if (st & 1) continue; for (int i = 0; i < k; i ++) mat[st][(st >> 1) | (1 << i)] = 1; } } friend inline Matrix operator * (Matrix x, Matrix y) { Matrix tmp = Matrix(x.n, y.m, 0); for (int i = 0; i < tmp.n; i ++) for (int k = 0; k < x.m; k ++) { if (x.mat[i][k]) { for (int j = 0; j < tmp.m; j ++) tmp.mat[i][j] = (tmp.mat[i][j] + x.mat[i][k] * y.mat[k][j] % mod) % mod; } } return tmp; } } f[N >> 4][N >> 1]; void init() { for (int k = 0; k <= 7; k ++) { f[k][1] = Matrix(k); for (int i = 2; i <= 60; i ++) f[k][i] = f[k][i - 1] * f[k][i - 1]; } } void solve() { ll n, k; cin >> n >> k; k = min(n, k); Matrix ans = Matrix(1, 1 << k, 0); ans.mat[0][0] = 1; for (ll i = 1, j = 1; j <= n; i ++, j <<= 1) if (n & j) ans = ans * f[k][i]; cout << ans.mat[0][0] << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); init(); int t; cin >> t; while (t --) solve(); return 0; }
F. Cidoai的数论求和
这个也是看官方题解补的,一堆数学公式,推公式+莫比乌斯反演。
代码
#include <iostream> #include <cmath> using namespace std; typedef long long ll; const int N = 4e6 + 10; int prime[N], mu[N], cnt; bool st[N]; ll n; void get_mu(int n) { mu[1] = 1; for (int i = 2; i <= n; i ++) { if (!st[i]) { prime[++ cnt] = i; mu[i] = -1; } for (int j = 1; prime[j] <= n / i; j ++) { st[i * prime[j]] = 1; if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } mu[i * prime[j]] = -mu[i]; } } } int main() { get_mu(N - 1); cin >> n; ll res= 0; ll m = sqrtl(n); for (ll i = 1; i <= m; i ++) { ll d = sqrtl(n / i / i / 2); res += mu[i] * d * d; } for (ll i = 1; i <= m; i ++) { ll t = n / i / i; ll u = sqrtl(t); ll d = sqrtl(t / 2); ll sum = 0; for (ll j = d + 1, ne; j <= u; j = ne + 1) { ne = t / (t / j); ne = min(ne, u); sum += t / j * (ne - j + 1); sum -= (ne - j + 1) * (j + ne) / 2; } res += mu[i] * sum * 2; } cout << res; return 0; }
本文作者:Natural_TLP
本文链接:https://www.cnblogs.com/Natural-TLP/p/18414878
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步