A. 相反数
Solution
签到题, 完全可以加大力度变成大数加法, 这里我直接贴了自己的大数加法模板
Code
#pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long long LL; const ll mod = 998244353; const int DEG = 20; const double PI = acos(-1.0); const double eps = 1e-10; const ll inf = 1e18; const int N = 1e6 + 5; static auto faster_iostream = []() { std::ios::sync_with_stdio(false); // turn off sync std::cin.tie(nullptr); // untie in/out streams return 0; }(); string add(string a, string b){ string c; if(a.size() > b.size()) swap(a, b); int len = min(a.size(), b.size()); int f = 0; for(int i = len - 1, j = b.size() - 1; i >= 0; i--, j--){ c += ((a[i] - '0' + b[j] - '0' + f) % 10) + '0'; f = (a[i] - '0' + b[j] - '0' + f) / 10; } for(int j = b.size() - a.size() - 1; j >= 0; j--){ c += ((b[j] - '0' + f) % 10) + '0'; f = (b[j] - '0' + f) / 10; } if(f){ c += '1'; } reverse(c.begin(), c.end()); return c; } int main(){ string s; cin >> s; string t = s; reverse(t.begin(), t.end()); cout << add(t, s) << "\n"; return 0; }
B. Music Problem
Solution
提供一个假的做法, 数据强一点可能只能bitset
题意简化一下就是让我们在数组中找出一组子序列的和为3600的倍数
然后这是一道原题的缩减版 原题地址https://ac.nowcoder.com/acm/contest/91/L?&headNav=www
考虑动态规划:表示和在模3600意义下的子序列的个数
我们用一个数组记录目前为止和在模3600意义下为i的子序列的个数
有
时间复杂度, 直接搞会超时, 当dp[0] > 0 的时候直接跳出剪枝就行了
Code
#pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long long LL; const ll mod = 998244353; const int DEG = 20; const double PI = acos(-1.0); const double eps = 1e-10; const ll inf = 1e18; const int N = 1e6 + 5; static auto faster_iostream = []() { std::ios::sync_with_stdio(false); // turn off sync std::cin.tie(nullptr); // untie in/out streams return 0; }(); int a[N]; int dp[4000], temp[4000]; int main(){ int t; cin >> t; while(t--){ int n; cin >> n; ll sum = 0; int flag = 0; memset(dp, 0, sizeof(dp)); memset(temp, 0, sizeof(temp)); for(int i = 1; i <= n; i++) cin >> a[i]; for(int i = 1; i <= n; i++){ if(dp[0] > 0) break; for(int j = 0; j < 3600; j++){ if(j == 0 || temp[j] != 0){ dp[(j + a[i]) % 3600] = temp[j] + 1; } if(dp[0] > 0) break; } for(int j = 0; j < 3600; j++){ temp[j] = max(temp[j], dp[j]); } } if(dp[0] > 0){ cout << "YES\n"; } else cout << "NO\n"; } return 0; }
C. 完全平方数
Solution
签到题, 先打个表, 然后lower_bound() 查找一下下标
注意0也是完全平方数!
Code
#pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long long LL; const ll mod = 998244353; const int DEG = 20; const double PI = acos(-1.0); const double eps = 1e-10; const ll inf = 1e18; const int N = 1e6 + 5; static auto faster_iostream = []() { std::ios::sync_with_stdio(false); // turn off sync std::cin.tie(nullptr); // untie in/out streams return 0; }(); ll dp[N]; ll solve(ll x){ int pos = lower_bound(dp + 1, dp + 1 + 100000, x) - dp; if(dp[pos] == x) return pos; else return pos - 1; } int main(){ int q; cin >> q; for(ll i = 0; i <= 1e5; i++){ dp[i + 1] = i * i; } while(q--){ ll l, r; cin >> l >> r; if(l >= 1) cout << solve(r) - solve(l - 1) << "\n"; else cout << solve(r) << "\n"; } return 0; }
D. 小H和游戏
Solution
因为只需要查询城市距离为2的节点,
对于城市u, 我们考虑用一个fa数组找到城市的祖先fa[u], 它的祖先的祖先就是fa[fa[u]]
因为只需要考虑距离为2以内的节点, 那么只需考虑上述三个节点
开一个cnt[N][3]的数组,
cnt[i][0] 表示 i 点本身的影响
cnt[i][1] 表示 i 点儿子的影响
cnt[i][2] 表示 i 点儿子的儿子的影响
每次查询我们都直接更新cnt数组即可
Code
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long long LL; const ll mod = 998244353; const int DEG = 20; const double PI = acos(-1.0); const double eps = 1e-10; const ll inf = 1e18; const int N = 1e6 + 5; static auto faster_iostream = []() { std::ios::sync_with_stdio(false); // turn off sync std::cin.tie(nullptr); // untie in/out streams return 0; }(); int tot, head[N]; struct Edge{ int v, nextz; }edge[N << 1]; void addedge(int u, int v){ edge[tot].v = v; edge[tot].nextz = head[u]; head[u] = tot++; } void init(){ tot = 0; memset(head, -1, sizeof(head)); } int fa[N]; void dfs(int u, int par){ fa[u] = par; for(int i = head[u]; ~i; i = edge[i].nextz){ int v = edge[i].v; if(v == par) continue; dfs(v, u); } } int cnt[N][3]; int main(){ init(); int n, m; cin >> n >> m; for(int i = 1; i <= n - 1; i++){ int u, v; cin >> u >> v; addedge(u, v); addedge(v, u); } dfs(1, 0); while(m--){ int u; cin >> u; cnt[u][1]++, cnt[u][2]++; cnt[fa[u]][0]++, cnt[fa[u]][1]++; cnt[fa[fa[u]]][0]++; cout << cnt[u][0] + cnt[fa[u]][1] + cnt[fa[fa[u]]][2] << "\n"; } return 0; }
E. 水题(water)
Solution
真·套娃题, 打个表我们发现f(i)其实就是个斐波那契数列, 然后我们只需要先判断x是不是斐波那契数
- 如果是的话, 对 m 做质因数分解统计贡献即可
对于求阶乘的尾0这类题
举个例子 求 13! 中 10进制下尾部0的个数
那么 因为 13! = 1 * 2 * ...... * 13;
考虑 10 的 质因子 2 和 5
其中 拥有质因子2的数字包括 2, 4, 6, 8, 10, 12
我们怎么求贡献呢?
我们发现 13 / 2 = 6 就是上面 6个数字的第一层贡献
6 / 2 = 3 就是第二层贡献(有的因子有两个2
3 / 2 = 1 就是第三层贡献
然后就没了, 总的贡献是 3 + 6 + 1 = 10
再考虑 质因子5的数字包括 5, 10
总的贡献是 13 / 5 = 2
两者取min, 得到13! 在10进制下有2个尾0
把这个结论推广到m进制 就是求m的质因子 再统计最小的贡献即可 - 不是的话就是个n皇后问题,模板贴一贴就好啦
Code
#pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long long LL; const ll mod = 1e9 + 7; const int DEG = 20; const double PI = acos(-1.0); const double eps = 1e-10; const ll inf = 1e18; const int N = 2e5 + 5; static auto faster_iostream = []() { std::ios::sync_with_stdio(false); // turn off sync std::cin.tie(nullptr); // untie in/out streams return 0; }(); // 1 ^ 2 + 1 ^ 2 = 1 * 2 // 1 ^ 2 + 1 ^ 2 + 2 ^ 2 = 2 * 3 // 1 ^ 2 + 1 ^ 2 + 2 ^ 2 + 3 ^ 2 = 3 * 5 int a[20], q; int ans = 0; void dfs(int k){ if(k == q + 1) { ans++; return ; } int flag = 0; for(int i = 1; i <= q; i++){ a[k] = i; // 第k个皇后在i行 flag = 1; for(int j = 1; j < k; j++){ if(a[j] == i || i - k == a[j] - j || i + k == a[j] + j){ flag = 0; break; } } if(flag){ dfs(k + 1); } } } ll F[100]; int main(){ ll x, m; cin >> x >> m; F[1] = F[2] = 1; for(int i = 3; i <= 90; i++){ F[i] = F[i - 1] + F[i - 2]; //cout << F[i] << "\n"; } int pos = -1; for(int i = 3; i <= 90; i++){ if(F[i] == x){ pos = i; break; } } if(pos == -1){ q = x % min(13LL, m) + 1; dfs(1); // n 皇后 cout << ans << "\n"; } else { vector<pair<int, int> > fac; for(int i = 2; i * i <= m; i++){ if(m % i == 0){ int cnt = 0; while(m % i == 0) m /= i, ++cnt; fac.push_back({i, cnt}); } } ll ans = 4e18; if(m > 1) fac.push_back({m, 1}); for(int i = 0; i < fac.size(); i++){ ll cur = x; ll res = 0; while(cur) res += cur / fac[i].first, cur /= fac[i].first; ans = min(ans, res / fac[i].second); } cout << ans << "\n"; } return 0; }