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;
}