B - Append
分析:就是个数组插入元素,查倒数的元素,没什么好说的
int a[N],b[N];
void solve() {
int n;
cin >> n;
vector<int> v;
while (n--) {
int op, x; cin >> op >> x;
if (op == 1) v.push_back(x);
else {
cout << v[v.size() - x] << endl;
}
}
}
C - Divide and Divide
分析:一开始是打表找规律,确实是找出规律了,但实现很麻烦。还是记忆化搜索吧。
可以推出 f(x) = f(x/2) + f(x-x/2) + x,是当n = x时,需要支付的代价。
得出这个递推式,就有两种思路了,要么dp要么递归
dp
时间复杂度O(n),注意到这题n很大,所以这个做法会tle
void solve() {
int n; cin >> n;
dp[2] = 2, dp[3] = 5;
for (int i = 4; i <= n; i++) {
dp[i] = dp[i / 2] + dp[i - i / 2] + i;
}
cout << dp[n];
}
记忆化搜索
用mp来记录,如果f(x)之前已经算过,就不必再递归。
int a[N],b[N];
map<int, int> mp;
int f(int x) {
if (x == 1) return 0;
if (mp[x] != 0) return mp[x];
return mp[x] = f(x / 2) + f(x - x / 2) + x;
}
void solve() {
int n; cin >> n;
cout << f(n) << endl;
}
D - Super Takahashi Bros.
知识点:链式前向星,dijkstra(堆优化)
分析:构建有向图,用dijkstra求最短路即可
int h[N], w[N], e[N], ne[N];
int idx = 0;//第idx条边
void add(int u, int v, int weight) {//当前正在输入第idx条边
//链式前向星是以边为单位的。
w[idx] = weight, e[idx] = v, ne[idx] = h[u];
h[u] = idx++;
//h[u]代表以u为起点,最后加的边的编号
}
int dist[N], st[N];
int n;
int dijkstra(int b) {
dist[b] = 0;
//st[b] = 1;
priority_queue<PII, vector<PII>, greater<PII> > heap;
//距离,编号
heap.push({ 0,b });
while (heap.size()) {
auto t = heap.top();
heap.pop();
int id = t.second, distance = t.first;
if (st[id]) continue;
st[id] = 1;
for (int i = h[id]; i != -1; i = ne[i]) {
int j = e[i];
if (distance + w[i] < dist[j]) {
dist[j] = distance + w[i];
heap.push({ dist[j],j });
}
}
}
return dist[n];
}
//16:12
int a[N],b[N];
void solve() {
memset(h, -1, sizeof h);
memset(dist, inf, sizeof dist);
cin >> n;
rep(i, 1, n-1) {
int t1, t2, x; cin >> t1 >> t2 >> x;
add(i, i + 1, t1);
add(i, x, t2);
}
cout << dijkstra(1) << endl;
}