A String Game
题意
给一个长度为 n n n 的字符串 s s s,输出将 s s s 前 x x x 个字符移植末尾的结果。
Solution
按题意模拟。( x x x 数量级较大,对 n n n 取模后缩小实际有效操作次数即可。
#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
题意
给定长度为 n n n 的数组 a a a,数组中每个数有 k k k 个可能取值,求数组 a a a 的最长上升子序列
Solution
题中保证给定的 k k k 个可能取值单调,且取值大小均小于1000,则考虑采用一个dp数组记录 d p [ i ] dp[i] dp[i] 表示以 i i i 数字结尾的最长上升子序列长度即可。
#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
题意
一张具有 n n n 个结点的有向图中,问每个节点能够到达的结点最小编号,输出排序去重后的结果。
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
题意
一共有 n n n 个糖果,每个糖果的甜度会随着时间变化。
每隔一个单位时间吃掉一个糖果,当吃掉编号为 i i i 的糖果时,需保证在吃这个糖果前编号比 i i i 大的糖果均被吃完;或者如果编号比 i i i 大的糖果没有吃完,则接下来必须将编号比 i i i 大的糖果吃完,即此时不能吃编号比 i i i 小的糖果。
Solution
构造一个糖果序列,考虑该以该序列作为吃糖顺序。
根据题目要求,要保证编号为 i i i 的糖果被吃掉之前或之后吃这个糖果前编号比 i i i 大的糖果均被吃完的情况,应依次从后往前考虑吃糖顺序。
当吃掉编号为 n n n 的糖时,接下来可以考虑是在吃编号为 n n n 的糖之前或之后吃编号为 n − 1 n-1 n−1 的糖, n − 2 n-2 n−2 同理,依此类推。于是假定当前已经确定编号大于 x + 1 x+1 x+1 的糖之后的吃糖顺序,接下考虑编号为 x x x 的糖在什么时候吃,此时有两种选择,在最开始的时候吃这颗糖,对答案的贡献为 a [ x ] + s u m [ x + 1 ] a[x]+sum[x+1] a[x]+sum[x+1] ,其中 s u m [ x + 1 ] sum[x+1] sum[x+1] 表示一个单位时间内编号大于 x x x 的糖甜度的变化之和;或者编号大于 x + 1 x+1 x+1 的糖全部吃完后吃这颗糖,对答案的贡献为 a [ x ] + d [ x ] ∗ ( n − x ) a[x]+d[x]*(n-x) a[x]+d[x]∗(n−x) ,其中 d [ x ] d[x] d[x] 表示单位时间内编号为 x x x 的糖甜度的变化值, n − x n-x n−x 表示这个糖在过了多久被吃掉。
#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;
}