牛客xiao白月赛45

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 2n1

于是
a n s = ∑ i = 1 n 2 ∗ i − 1 = n 2 ans = \sum\limits_{i = 1} ^ n 2*i - 1 = n ^ 2 ans=i=1n2i1=n2

inline void solve(){
    ll n;
    cin >> n;
    cout << n * n;
}
C 山楂
题意

我们可以将 34 i i i 级糖果合并,升级成为一个高一级的糖果并且获得 x ∗ i x∗i xi 点积分, 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} 2cnt1

(当然最后算这个数不用快速幂也可以过,但作为一个合格的算法竞赛选手,看到求幂看到取模自然会联想到快速幂)

考虑 − 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]+iemax(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])(1in),那么最后的 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值