牛客IOI周赛28-普及组
A String Game
题意
给一个长度为 的字符串 ,输出将 前 个字符移植末尾的结果。
Solution
按题意模拟。( 数量级较大,对 取模后缩小实际有效操作次数即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, j, k) for (ll(i) = (j); (i) <= (k); (++i)) void solve() { ll n, x; string s; cin >> n >> x >> s; x %= n; rep(i, x, n - 1) cout << s[i]; rep(i, 0, x - 1) cout << s[i]; cout << endl; } signed main() { solve(); return 0; }
B Sequence Game
题意
给定长度为 的数组 ,数组中每个数有 个可能取值,求数组 的最长上升子序列
Solution
题中保证给定的 个可能取值单调,且取值大小均小于1000,则考虑采用一个dp数组记录 表示以 数字结尾的最长上升子序列长度即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, j, k) for (ll(i) = (j); (i) <= (k); (++i)) #define mem(x, y) memset(x, y, sizeof(x)) typedef long long ll; const int N = 1e6 + 7; int n, k, ans, tmp[N], dp[N]; signed main() { cin >> k >> n; rep(i, 1, n) { int mx = 0, now = 0, x; mem(tmp, 0); rep(j, 1, k) { cin >> x; while (now < x) mx = max(mx, dp[now]), now++; tmp[x] = mx + 1; } rep(j, 0, 1000) dp[j] = max(tmp[j], dp[j]), ans = max(ans, dp[j]); } cout << ans; return 0; }
C Simple Game
题意
一张具有 个结点的有向图中,问每个节点能够到达的结点最小编号,输出排序去重后的结果。
Solution
一开始没仔细想,直接建图跑dfs,然后更新访问结点,结果发现如果简单判环走到走过的地方就不走的时候,结点的更新不及时导致环路上其他结点同样不能及时更新,95分代码,其实数据强一点不可能会这么高得分的
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, j, k) for (ll(i) = (j); (i) <= (k); (++i)) const int N = 1e5 + 7; vector<ll> to[N]; ll ans[N]; bool vis[N]; ll dfs(int p) { if (vis[p]) return ans[p]; vis[p] = 1; for (auto i : to[p]) ans[p] = min(ans[p], dfs(i)); return ans[p]; } signed main() { ll n, m, u, v; cin >> n >> m; rep(i, 1, n) ans[i] = i; rep(i, 1, m) cin >> u >> v, to[u].emplace_back(v); rep(i, 1, n) dfs(i); vector<ll> a; rep(i, 1, n) a.emplace_back(ans[i]); sort(a.begin(), a.end()), a.erase(unique(a.begin(), a.end()), a.end()); for (auto i : a) cout << i << ' '; return 0; }
正解应该建反图,然后直接跑dfs即可,从小到大第一次访问到的即为当前结点能到达的最小值。
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, j, k) for (ll(i) = (j); (i) <= (k); (++i)) const int N = 1e5 + 7; vector<ll> to[N]; int ans[N]; bool vis[N]; void dfs(int fa, int p) { ans[p] = min(ans[p], fa); if (vis[p]) return; vis[p] = 1; for (auto i : to[p]) dfs(ans[p], i); } signed main() { int n, m, u, v; cin >> n >> m; rep(i, 1, n) ans[i] = i; rep(i, 1, m) cin >> u >> v, to[v].emplace_back(u); rep(i, 1, n) dfs(i, i); vector<ll> a; rep(i, 1, n) a.emplace_back(ans[i]); sort(a.begin(), a.end()), a.erase(unique(a.begin(), a.end()), a.end()); for (auto i : a) cout << i << ' '; return 0; }
D Sweet Game
题意
一共有 个糖果,每个糖果的甜度会随着时间变化。
每隔一个单位时间吃掉一个糖果,当吃掉编号为 的糖果时,需保证在吃这个糖果前编号比 大的糖果均被吃完;或者如果编号比 大的糖果没有吃完,则接下来必须将编号比 大的糖果吃完,即此时不能吃编号比 小的糖果。
Solution
构造一个糖果序列,考虑该以该序列作为吃糖顺序。
根据题目要求,要保证编号为 的糖果被吃掉之前或之后吃这个糖果前编号比 大的糖果均被吃完的情况,应依次从后往前考虑吃糖顺序。
当吃掉编号为 的糖时,接下来可以考虑是在吃编号为 的糖之前或之后吃编号为 的糖, 同理,依此类推。于是假定当前已经确定编号大于 的糖之后的吃糖顺序,接下考虑编号为 的糖在什么时候吃,此时有两种选择,在最开始的时候吃这颗糖,对答案的贡献为 ,其中 表示一个单位时间内编号大于 的糖甜度的变化之和;或者编号大于 的糖全部吃完后吃这颗糖,对答案的贡献为 ,其中 表示单位时间内编号为 的糖甜度的变化值, 表示这个糖在过了多久被吃掉。
#include <bits/stdc++.h> using namespace std; #define int ll #define rep(i, j, k) for (ll(i) = (j); (i) <= (k); (++i)) #define rrep(i, j, k) for (ll i = (ll)(j); i >= (ll)(k); i--) typedef long long ll; const int N = 1e5 + 7; ll a[N], d[N], sum[N], n, l, r; signed main() { cin >> n; rep(i, 1, n) cin >> a[i]; rep(i, 1, n) cin >> d[i]; rrep(i, n, 1) sum[i] = d[i] + sum[i + 1]; ll ans = a[n]; rrep(i, n - 1, 1) ans += a[i] + max(sum[i + 1], d[i] * (n - i)); cout << ans << '\n'; return 0; }