1. 现值计算
模拟即可
代码:
#include<bits/stdc++.h>
using namespace std;
signed main() {
int n;
double e;
cin >> n >> e;
vector<int> a(n + 1);
double ans = 0;
for(int i = 0; i <= n; i++) {
cin >> a[i];
ans += a[i] * pow(1. + e, -i);
}
cout << fixed << setprecision(10) << ans << "\n";
return 0;
}
2. 训练计划
先把树建出来,dfs下去的时候记一下最早的时间,回溯的时候记录最晚时间。
代码:
#include<bits/stdc++.h>
using namespace std;
signed main() {
int n, m;
cin >> m >> n;
vector<vector<int>> adj(n + 1);
vector<int> t(n + 1), vis(n + 1);
for(int i = 1; i <= n; i++) {
int p; cin >> p;
adj[p].push_back(i);
}
for(int i = 1; i <= n; i++) {
cin >> t[i];
}
vector<int> early(n + 1), late(n + 1);
function<void(int, int, int)> dfs = [&] (int u, int fa, int curt) {
vis[u] = 1;
early[u] = curt;
late[u] = m - t[u] + 1;
for(auto v : adj[u]) {
dfs(v, u, curt + t[u]);
late[u] = min(late[u], late[v] - t[u]);
}
};
for(int i = 1; i <= n; i++) {
if(!vis[i]) {
dfs(i, 0, 1);
}
}
int notwoline = 0;
for(int i = 1; i <= n; i++) {
cout << early[i] << " ";
if(early[i] + t[i] - 1 > m) {
// cerr << "fuck:" << i << "\n";
notwoline = 1;
}
}
if(notwoline) {
return 0;
}
cout << "\n";
for(int i = 1; i <= n; i++) {
cout << late[i] << " ";
}
return 0;
}
3. JPEG 解码
按照公式模拟即可
代码:
#include<bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
signed main() {
vector<vector<int>> Q(8, vector<int> (8));
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
cin >> Q[i][j];
}
}
int n; cin >> n;
int T; cin >> T;
int x, y;
x = y = 0;
//右,左下,下,右上
int dx[] = {0, 1, 1, -1};
int dy[] = {1, -1, 0, 1};
int d = -1;
vector<vector<int>> M(8, vector<int> (8));
for(int i = 1; i <= n; i++) {
int cur = 0;
cin >> cur;
if(d == -1) {
d = 0;
} else if(d == 0) {
if(x == 0) {
d = 1;
} else {
d = 3;
}
} else if(d == 1) {
if(x == 7) {
d = 0;
} else if(y == 0) {
d = 2;
}
} else if(d == 2) {
if(y == 0) {
d = 3;
} else {
d = 1;
}
} else if(d == 3) {
if(y == 7) {
d = 2;
} else if(x == 0) {
d = 0;
}
}
M[x][y] = cur;
x += dx[d];
y += dy[d];
}
auto MQ = M;
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
MQ[i][j] *= Q[i][j];
}
}
auto Mc = MQ;
auto alpha = [&] (int u) {
if(u == 0) {
return sqrt(0.5);
} else {
return 1.0;
}
};
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
double sum = 0;
for(int ii = 0; ii < 8; ii++) {
for(int jj = 0; jj < 8; jj++) {
sum += alpha(ii) * alpha(jj) * MQ[ii][jj] * cos(pi / 8 * (i + 0.5) * ii) * cos(pi / 8 * (j + 0.5) * jj);
}
}
sum /= 4;
double temp = sum + 128;
Mc[i][j] = min((int) (sum + 128.5), 255);
Mc[i][j] = max(Mc[i][j], 0);
assert(Mc[i][j] >= 0);
}
}
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
if(T == 0) {
cout << M[i][j] << ' ';
} else if(T == 1) {
cout << MQ[i][j] << " ";
} else if(T == 2) {
cout << Mc[i][j] << " ";
} else {
assert(0);
}
}
cout << "\n";
}
return 0;
}
4. 聚集方差
树上启发式合并,用 multiset 维护当前的值的集合,用 val 记录当前的答案,每进来一个值现在 multiset 里面找前驱和后继,因为新进来的值可能对这俩造成影响,然后再把离自己近的加到答案里面。复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define int long long
signed main() {
int n; cin >> n;
vector<vector<int>> adj(n + 1);
vector<int> a(n + 1);
for(int i = 2; i <= n; i++) {
int p;
cin >> p;
adj[p].push_back(i);
}
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> hson(n + 1), top(n + 1), sz(n + 1);
function<void(int)> dfs1 = [&] (int u) {
sz[u] = 1;
for(auto v : adj[u]) {
dfs1(v);
if(!hson[u] || sz[hson[u]] < sz[v]) {
hson[u] = v;
}
sz[u] += sz[v];
}
};
function<void(int, int)> dfs2 = [&] (int u, int tp) {
top[u] = tp;
if(hson[u]) {
dfs2(hson[u], tp);
}
for(int v : adj[u]) {
if(v == hson[u]) continue;
dfs2(v, v);
}
};
dfs1(1);
dfs2(1, 1);
// cerr << "hson:";
// for(int i = 1; i <= n; i++) {
// cerr << hson[i] << " ";
// }
// cerr << "\n";
multiset<int> st;
ll val = 0;
function<void(int, int)> calc = [&] (int u, int curhson) {
// cerr << "calc:" << u << "\n";
// st[i-1] st[i] ... a[u] =?= st[i+1] st[i+2]
//it: *
multiset<int>::iterator it = st.lower_bound(a[u]);
ll cur = (st.size() == 0 ? 0 : (ll) 1e18);
if(it != st.end()) {
cur = min(cur, 1ll * (a[u] - *it) * (a[u] - *it));
}
if(it != st.begin()) {
multiset<int>::iterator it_pre = prev(it);
// st[i-1] st[i] ... a[u] =?= st[i+1] st[i+2]
//it_pre: *
cur = min(cur, 1ll * (a[u] - *it_pre) * (a[u] - *it_pre));
}
auto update = [&] (ll a, ll b, ll c, ll d) {
// st[i-1] st[i] st[i+1] a[u]
ll origin = min(b - a, c - b);
if(origin > abs(d - b)) {
val -= 1ll * origin * origin;
val += 1ll * (d - b) * (d - b);
}
};
val += cur;
if(st.size() == 1) {
val += 1ll * (*st.begin() - a[u]) * (*st.begin() - a[u]);
} else if(st.size() != 0) {
if(it != st.begin()) {
auto it_pre = prev(it);
// s[i]
ll ta, tb, tc;
if(it_pre != st.begin()) {
ta = *prev(it_pre);
} else {
ta = -2e9;
}
tb = *it_pre;
if(it != st.end()) {
tc = *it;
} else {
tc = 2e9;
}
update(ta, tb, tc, a[u]);
}
if(it != st.end()) {
ll ta, tb, tc;
if(it != st.begin()) {
ta = *prev(it);
} else {
ta = -2e9;
}
tb = *it;
if(next(it) != st.end()) {
tc = *next(it);
} else {
tc = 2e9;
}
update(ta, tb, tc, a[u]);
}
}
// cerr << "calc_val:" << val << "\n";
st.insert(a[u]);
for(int v : adj[u]) {
if(v == curhson) continue;
calc(v, curhson);
}
};
vector<ll> ans(n + 1);
function<void(int, int)> dsu_on_tree = [&] (int u, int keep) {
// cerr << "dsu_on_tree:" << u << " " << keep << "\n";
for(int v : adj[u]) {
if(v == hson[u]) continue;
dsu_on_tree(v, 0);
}
if(hson[u]) dsu_on_tree(hson[u], 1);
calc(u, hson[u]);
ans[u] = val;
if(!keep) {
st.clear();
val = 0;
}
};
dsu_on_tree(1, 0);
for(int i = 1; i <= n; i++) {
cout << ans[i] << "\n";
}
return 0;
}
5. 星际网络
究极毒瘤题,线段树优化建图+CF464E
简单的来说,先用线段树优化建图,然后跑dijkstra
dij的边权用一个长度
1
0
5
10^5
105 的线段树维护,对于加法,直接线段树上二分单点加和区间清零即可,对于cmp,用线段树二分前缀hash找到最长公共前缀,比较下一位就行。
对于空间,容易发现都是在原来的基础上加的,用主席树动态开点可以解决。
太恶心了 没有代码