A - 369
给定两个数
a
,
b
a,b
a,b,求有几个数
c
c
c满足
a
,
b
,
c
a,b,c
a,b,c三个数组成的数列(顺序任意)为等差数列
签到题。只有三种顺序 a b c , c a b , a c b abc,cab,acb abc,cab,acb,求集合个数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int main(){
//freopen("in.txt", "r", stdin);
int a, b;
cin >> a >> b;
set<int> s;
s.insert(a * 2 - b);
s.insert(b * 2 - a);
if ((a + b) % 2 == 0) s.insert((a + b) / 2);
cout << s.size() << endl;
return 0;
}
B - Delimiter
给定
N
N
N长度的序列
A
i
,
S
i
A_i,S_i
Ai,Si
A
i
A_i
Ai代表键的位置
S
i
S_i
Si为
L
L
L时代表左手弹奏序列,
R
R
R时代表右手序列
求最小化的左手移动距离+右手移动距离
签到题2。模拟,手的初始位置在第一个点上即可。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int n;
int l = -1, r = -1;
int main(){
//freopen("in.txt", "r", stdin);
cin >> n;
int ans = 0;
for (int i = 0; i < n; ++i) {
int a;
char c;
cin >> a >> c;
if (c == 'L') {
if (l != -1) ans += abs(a - l);
l = a;
}
else {
if (r != -1) ans += abs(a - r);
r = a;
}
}
cout << ans << endl;
return 0;
}
C - Count Arithmetic Subarrays
N
N
N长度序列
A
i
A_i
Ai
求连续子串为等差数列的个数
签到题3 .对于每个元素记录和前一个值的差
d
i
d_i
di,同时记录下当前等差数列的长度
c
c
c。如果之前的
d
i
−
1
d_{i-1}
di−1和
d
i
d_i
di相同那么
c
+
=
1
c+=1
c+=1否则
c
=
1
c=1
c=1
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int n;
ll a[200020];
ll d;
int main(){
//freopen("in.txt", "r", stdin);
cin >> n;
ll ans = n;
for (int i = 1; i <= n; ++i) cin >> a[i];
d = 1ll << 60;
ll c = 0;
for (int i = 2; i <= n; ++i) {
if (a[i] - a[i - 1] == d) {
c++;
}
else {
d = a[i] - a[i - 1];
c = 1;
}
ans += c;
}
cout << ans << endl;
return 0;
}
D - Bonus EXP
N
N
N长度序列
A
i
A_i
Ai中 任取一子序列记为
B
B
B
b
1
,
b
2
,
b
3
.
.
.
b
n
b_1,b_2,b_3...b_n
b1,b2,b3...bn为
B
B
B值
s
=
b
1
+
b
2
∗
2
+
b
3
+
b
4
∗
2
+
.
.
.
s=b_1+b_2*2+b_3+b_4*2+...
s=b1+b2∗2+b3+b4∗2+...
最大化
s
s
s
奇偶递推
设当前取完位置
i
i
i时取奇数个元素得到的最大值为
f
(
i
,
1
)
f(i,1)
f(i,1),偶数个元素得到最大值为
f
(
i
,
0
)
f(i,0)
f(i,0)
f
(
i
,
1
)
=
m
a
x
(
f
(
i
−
1
,
0
)
+
a
i
,
f
(
i
−
1
,
1
)
)
f(i,1)=max(f(i-1,0)+a_i,f(i-1,1))
f(i,1)=max(f(i−1,0)+ai,f(i−1,1))
f
(
i
,
0
)
=
m
a
x
(
f
(
i
−
1
,
1
)
+
a
i
∗
2
,
f
(
i
−
1
,
0
)
)
f(i,0)=max(f(i-1,1)+a_i*2,f(i-1,0))
f(i,0)=max(f(i−1,1)+ai∗2,f(i−1,0))
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
ll a[200020];
ll f[200020][2];
int n;
int main(){
//freopen("in.txt", "r", stdin);
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
memset(f, 0xf7, sizeof(f));
f[0][0] = 0;
for (int i = 1; i <= n; ++i) {
f[i][0] = max(f[i - 1][0], f[i - 1][1] + a[i] * 2);
f[i][1] = max(f[i - 1][1], f[i - 1][0] + a[i]);
}
printf("%lld\n", max(f[n][0], f[n][1]));
return 0;
}
E - Sightseeing Tour
无向图中给定 K K K条边,要求从点1经过这些边(顺序不定),最后到达点N的最短旅行距离
注意到 K ≤ 5 K \leq5 K≤5,那么枚举这些边的访问顺序和边内点的访问顺序,然后在不同的边之间用最短距离连接。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int n, m;
ll d[404][404];
struct Edge {
int u, v;
ll w;
};
Edge e[200020];
int q;
void solve() {
int K;
cin >> K;
vi seq;
while (K--) {
int t;
cin >> t;
seq.push_back(t);
}
sort(seq.begin(), seq.end());
int l = seq.size();
ll ans = 1ll << 60;
for (int i = 0; i < (1 << l); ++i) {
do {
int cur = 1;
ll cost = 0;
for (int j = 0; j < l; ++j) {
int idx = seq[j];
auto [u, v, w] = e[idx];
if ((i >> j) & 1) swap(u, v);
cost += d[cur][u] + w;
cur = v;
}
cost += d[cur][n];
ans = min(ans, cost);
//printf("%lld\n", ans);
} while (next_permutation(seq.begin(), seq.end()));
}
printf("%lld\n", ans);
}
int main(){
//freopen("in.txt", "r", stdin);
cin >> n >> m;
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= n; ++i) d[i][i] = 0;
for (int i = 1; i <= m; ++i) {
int u, v;
ll w;
cin >> u >> v >> w;
d[u][v] = min(d[u][v], w);
d[v][u] = min(d[v][u], w);
e[i] = Edge({ u, v, w });
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
for (int k = 1; k <= n; ++k) {
if (d[j][i] + d[i][k] < d[j][k]) d[j][k] = d[j][i] + d[i][k];
}
}
}
cin >> q;
while (q--) {
solve();
}
return 0;
}
F - Gather Coins
非常大的图中只能往右或者往下走,给定 N N N个点,求最多能走到几个点,并求路线
不错的500分题。
首先对点按照rc排序,然后dp。每个点坐标
R
i
,
C
i
R_i,C_i
Ri,Ci,要求一条经过当前点的路径能覆盖几个点,就是求之前从第1列到第c列的点中最多能覆盖几个点然后+1。即为一个区间查询最值问题。可以用线段树解。第二问求路径,可在线段树中记录下每一个最值代表的点索引,然后从后往前迭代求解。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int h, w, n;
const int N = 200002;
vector<pii> seq;
struct Node{
int l, r;
int mx;
int idx;
};
Node tr[N << 2];
#define lu (u * 2)
#define ru (u * 2 + 1)
void build(int l, int r, int u) {
tr[u].l = l, tr[u].r = r;
if (l == r) return;
int mi = (l + r) / 2;
build(l, mi, lu);
build(mi + 1, r, ru);
}
void push_up(int u) {
if (tr[lu].mx > tr[ru].mx) {
tr[u].mx = tr[lu].mx;
tr[u].idx = tr[lu].idx;
}
else {
tr[u].mx = tr[ru].mx;
tr[u].idx = tr[ru].idx;
}
}
void update(int idx, int y, int u, int val) {
if (tr[u].l == tr[u].r) {
tr[u].mx = val; tr[u].idx = idx;
return;
}
int mi = (tr[u].l + tr[u].r) / 2;
if (y <= mi) update(idx, y, lu, val);
else update(idx, y, ru, val);
push_up(u);
}
Node query(int l, int r, int u) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u];
Node ret({ 0, 0, 0, 0 });
int mi = (tr[u].l + tr[u].r) / 2;
if (l <= mi) {
Node ln = query(l, r, lu);
if (ret.mx < ln.mx)
ret = ln;
}
if (r > mi) {
Node rn = query(l, r, ru);
if (ret.mx < rn.mx)
ret = rn;
}
return ret;
}
int main(){
//freopen("in.txt", "r", stdin);
cin >> h >> w >> n;
for (int i = 1; i <= n; ++i) {
int r, c;
cin >> r >> c;
seq.push_back({ r, c });
}
sort(seq.begin(), seq.end());
build(1, w, 1);
unordered_map<int, int> path;
for (int i = 0; i < n; ++i) {
auto [x, y] = seq[i];
Node ret = query(1, y, 1);
update(i + 1, y, 1, ret.mx + 1);
path[i + 1] = ret.idx;
//printf("%d %d\n", i + 1, ret.idx);
}
Node rt = query(1, w, 1);
int ans = rt.mx;
printf("%d\n", ans);
int lst = rt.idx;
string s = "";
int cx = h, cy = w;
while (lst != 0) {
auto [x, y] = seq[lst - 1];
for (int i = 0; i < cx - x; ++i) s += "D";
for (int i = 0; i < cy - y; ++i) s += "R";
lst = path[lst];
cx = x, cy = y;
}
for (int i = 0; i < cx - 1; ++i) s += "D";
for (int i = 0; i < cy - 1; ++i) s += "R";
reverse(s.begin(), s.end());
cout << s << endl;
return 0;
}
但是线段树很费时间,有更简单的做法吗?
答案是有。
观察rc排序后的坐标点对,很容易发现这就是一个求最大不下降子序列问题。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int h, w, n;
pii seq[200002];
int pre[200002];
int main(){
//freopen("in.txt", "r", stdin);
cin >> h >> w >> n;
for (int i = 1; i <= n; ++i) {
int x, y;
cin >> x >> y;
seq[i] = { x, y };
}
sort(seq + 1, seq + n + 1);
vi b, p;
for (int i = 1; i <= n; ++i) {
auto [x, y] = seq[i];
int pos = upper_bound(b.begin(), b.end(), y) - b.begin();
if (pos == b.size()) {
b.push_back(y);
p.push_back(i);
}
else {
b[pos] = y;
p[pos] = i;
}
if(pos - 1 >= 0)
pre[i] = p[pos - 1];
}
printf("%d\n", b.size());
string s;
int cx = h, cy = w;
int pos = p.back();
while (pos != 0) {
auto [x, y] = seq[pos];
for (int i = 0; i < cx - x; ++i) s += "D";
for (int i = 0; i < cy - y; ++i) s += "R";
pos = pre[pos];
cx = x, cy = y;
}
for (int i = 0; i < cx - 1; ++i) s += "D";
for (int i = 0; i < cy - 1; ++i) s += "R";
reverse(s.begin(), s.end());
cout << s << endl;
return 0;
}
G - As far as possible
给出一颗边上有权重
L
i
Li
Li的树
T
T
T
对于每个
1...
N
1...N
1...N的值
K
K
K
在树上选出
K
K
K个点,最大化从点1访问这些点并且最后需要回到点1的最短路径
K
=
1
K=1
K=1时,明显是选从1作为根节点开始访问,最长路径的叶子结点
之后显然需要选取叶子节点。当然不能算出所有叶子节点的路径长度然后排序。
设dfs(u)计算u节点到叶子节点的最长路径,
d
f
s
(
u
)
=
max
(
d
f
s
(
v
)
+
w
(
u
,
v
)
)
dfs(u)=\max (dfs(v)+w(u,v))
dfs(u)=max(dfs(v)+w(u,v))
那么那些不在最长路径上的v就是后面可以插入的路径。
最后把这些路径值排序,依次加入答案中。
那些在最长路径上的v对于答案共享为0.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int n;
vector<pair<int, ll>> g[200002];
vector<ll> ans;
ll dfs(int u, int f) {
ll mx = 0;
for (auto [v, w] : g[u]) {
if (v == f)
continue;
ll t = dfs(v, u) + w;
if (t > mx) {
ans.push_back(mx);
mx = t;
}
else {
ans.push_back(t);
}
}
return mx;
}
int main(){
freopen("in.txt", "r", stdin);
cin >> n;
for (int i = 0; i < n - 1; ++i) {
int u, v;
ll w;
cin >> u >> v >> w;
g[u].push_back({ v, w });
g[v].push_back({ u, w });
}
ans.push_back(dfs(1, 0));
sort(ans.begin(), ans.end(), greater<ll> ());
ll t = 0;
for (ll x : ans) {
t += x;
printf("%lld\n", t * 2);
}
return 0;
}