A 悬崖
题意
两个墙之间相距 n n n 米, 每秒钟两墙距离会减 1 1 1 ,小沙每秒跳一次可跳 x x x 米(可斜着跳也可以直着跳),在保证小沙不摔下去的前提下,小沙最多可跳多少次。
题解
签到题,但要特别注意 x < n x < n x<n ,小沙跳 x x x 米,而不是 0 0 0 米
inline void solve(){
ll n, x;
cin >> x >> n;
if (n > x){
cout << x;
return;
}
cout << n * x;
}
B 数数
题意
给你一段程序
void dfs(int cnt){//cnt从1开始 如同dfs(1)
for(int i=1;i<=cnt;i++)ans++;
dfs(cnt+2);
}
和一个 n n n, 问你这个递归 n n n 次后全局变量 a n s ans ans 的值是多少
题解
模拟一下发现第一层 a n s ans ans 会加 1 1 1,第二层加 3 3 3 ,第三层加 5 5 5 … 第 n n n 层加 2 ∗ n − 1 2 * n - 1 2∗n−1
于是
a
n
s
=
∑
i
=
1
n
2
∗
i
−
1
=
n
2
ans = \sum\limits_{i = 1} ^ n 2*i - 1 = n ^ 2
ans=i=1∑n2∗i−1=n2
inline void solve(){
ll n;
cin >> n;
cout << n * n;
}
C 山楂
题意
我们可以将 3 或 4 个 i i i 级糖果合并,升级成为一个高一级的糖果并且获得 x ∗ i x∗i x∗i 点积分, x x x 为消耗同级糖果的数量, i i i 为你消耗的糖果等级,当你拥有了一个9级糖果也就代表你有了一串山楂串,这个时候你的 9 级糖果就会消失。
现在给你每级糖果若干个,求最后的分的最大值。
题解
3 x + 4 y 3x + 4y 3x+4y 可以表示出除了 1 , 2 , 5 1, 2, 5 1,2,5 外的所有数
也就是说除了 1 , 2 , 5 1,2,5 1,2,5 外的所有数都可以全部穿成下一级,所获得的积分是 a [ i ] ∗ i a[i] * i a[i]∗i
贪心的想一下,最高级的糖果最多答案最优,因为 a [ i + 1 ] = a [ i ] / 3 a[i + 1] = a[i] / 3 a[i+1]=a[i]/3
而对于 a [ i ] = = 5 a[i] == 5 a[i]==5, 无论是串成 3 3 3 个还是 4 4 4 个下一级增长的糖果的数量均为 1 1 1 ,而我们为了让当前得分最多,于是串 4 4 4 个。
inline void solve(){
for (int i = 1; i <= 8; i++) cin >> a[i];
ll ans = 0;
for (int i = 1; i <= 8; i++){
if (a[i] < 3) continue;
if (a[i] == 5){
ans += 4 * i;
a[i + 1] += 1;
continue;
}
ans += a[i] * i;
a[i + 1] += a[i] / 3;
}
cout << ans;
}
D 切糕
题意
合法括号串:指对于一个字符串他的左括号数量和右括号一样多,且对于任意前缀左括号始终不小于右括号数。
前缀:指字符串的从第一个字符开始,到任意字符停止的一个字符串。
小沙可以在两个合法括号串之间切一刀,问最后有多少种切法。
题解
设最后有 c n t cnt cnt 个合法括号串,那么切法为 2 c n t − 1 2^{cnt - 1} 2cnt−1
(当然最后算这个数不用快速幂也可以过,但作为一个合格的算法竞赛选手,看到求幂看到取模自然会联想到快速幂)
考虑 − 1 -1 −1 的情况
- 对于某一段字串右括号的数量严格大于左括号的数量
- 遍历完整个字符串后,左括号还有剩余
const ll mod = 1e9 + 7;
ll qpow(ll a ,ll b, ll p){
ll ans = 1 % p;
while(b){
if (b & 1) ans = 1ll * (ans * a) %p;
a = (a * a) % p;
b >>= 1;
}
return ans;
}
inline void solve(){
string s;
cin >> s;
ll num = 0;
ll cnt = 0;
for (auto i : s){
if (i == '(') num++;
else {
num--;
if (num == 0) cnt ++;
if (num < 0){
cout << -1 << endl;
return;
}
}
}
if (num) {
cout << "-1";
return;
}
ll ans = 1;
cout << qpow(2ll, cnt - 1, mod);
}
E 筑巢
题意
给定你一个 n n n 个节点的树,你需要在树上选取一个非空连通块,使其舒适度和最大。选择的边和点的舒适度都是舒适度。
题解
考虑树上背包,设 d p [ u ] dp[u] dp[u] 表示以 u u u 的祖先的子树最大的舒适值
转移方程
d
p
[
u
]
=
a
[
u
]
+
∑
i
∈
e
max
(
0
,
d
p
[
i
.
t
o
]
+
w
[
i
]
)
dp[u] = a[u] + \sum\limits_{i \in e}\max(0, dp[i.to]+w[i])
dp[u]=a[u]+i∈e∑max(0,dp[i.to]+w[i])
因为是非空联通块,所以
a
n
s
ans
ans 的初始值要设置成
−
inf
-\inf
−inf
考虑所有的点权和边权均为 − 1 e 9 -1e9 −1e9,若 a n s ans ans 设为 0 0 0, a n s = max ( a n s , d p [ i ] ) ( 1 ≤ i ≤ n ) ans = \max(ans,dp[i]) (1 \le i \leq n) ans=max(ans,dp[i])(1≤i≤n),那么最后的 a n s ans ans 为 0 0 0,显然非空联通的舒适度 < 0 <0 <0。
const int maxn = 1e5 + 10;
ll a[maxn];
int head[maxn << 1], to[maxn << 1] ;
ll w[maxn << 1];
int nex[maxn << 1];
int tot;
ll dp[maxn];
void add(int fa, int t, ll val){
to[++tot] = t, w[tot] = val;
nex[tot] = head[fa], head[fa] = tot;
}
ll ans = -1e9;
void dfs(int node, int fa){
dp[node] = a[node];
for (int i = head[node]; i ; i = nex[i]){
int child = to[i];
if (to[i] == fa) continue;
dfs(child, node);
dp[node] += max(0ll, dp[child] + w[i]);
ans = max(ans, dp[node]);
}
}
inline void solve(){
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n - 1; i++){
int f, t;
ll w;
cin >> f >> t >> w;
add(f, t, w);
add(t, f, w);
}
dfs(1, 0);
cout << ans;
}