牛客NowCoder OI周赛普及组14题解

牛客NowCoder OI周赛普及组14题解

A. String

题目

在这里插入图片描述
开一个数组直接统计。

#include <iostream>
#include <cstring>
using namespace std;
int a[300];
string s;
int main() {
    cin >> s ;
    int cnt = 0;
    for (int i = 0; i < s.length(); i++) {
        if (a[s[i]]++ == 0) cnt++;
    }
    cout << cnt << endl;
    return 0;
}

B.Number

题目

在这里插入图片描述
模拟,但是提前打一个表,这样可以快速得到任何一个数的n次幂,防止超时。

#include <iostream>
using namespace std;
typedef long long ll;
ll pow[10][30];
 
bool check(ll x) {
    for (int j = 1; j <= 21; j++) {
        ll sum = 0, tmp = x;
        while(tmp) {
            sum += pow[tmp%10][j];
            tmp /= 10;
        }
        if (sum == x) return true;
        else if (sum > x) return false;
    }
    return false;
}
 
int main() {
    for (int i = 1; i <= 9; i++) {
        pow[i][1] = i;
        for (int j = 2; j <= 21; j++)
            pow[i][j] = pow[i][j-1] * i;
    }
     
    int n; cin >> n;
    ll v; int cnt = 0;
    for (int i = 0; i < n; i++) {
        cin >> v;
        if (check(v)) cnt++;
    }
    cout << cnt << endl;
    return 0;
}

C.Tree

题目

思路

树形dp,换根。首先把无根树变成有根树,不妨选择1作为根,由此求出两个值(1) s i z [ v ] siz[v] siz[v] 和(2) d e p [ v ] dep[v] dep[v],分别代表以 v v v为根节点的子树的尺寸和深度和。
接下来考虑换根的状态转移。
f [ v ] f[v] f[v]为以 v v v为根的价值总和,那么让根往他的子节点 u u u去转移,则可得到方程如下:
f [ u ] = f [ v ] + n − s i z [ u ] − s i z [ u ] f[u]=f[v]+n-siz[u]-siz[u] f[u]=f[v]+nsiz[u]siz[u]
f [ u ] = f [ v ] + n − 2 ∗ s i z [ u ] f[u] =f[v]+n-2*siz[u] f[u]=f[v]+n2siz[u]
(对于所有处 u u u子树的节点,距离加1,所有在其子树上的节点,距离减1)
递归的去求得 f f f数组。最后找到最大值即可。

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int mxN = 1e6 + 10;
int siz[mxN], dep[mxN], f[mxN];
vector<int> G[mxN];
int n, ans;
 
void dfs(int v, int p) {
    dep[v] = dep[p] + 1;
    siz[v] = 1;
    for (auto u : G[v]) {
        if (u == p) continue;
        dfs(u, v);
        siz[v] += siz[u];
    }  
}
 
void solve(int v, int p) {
    for (auto u : G[v]) {
        if (u == p) continue;
        f[u] = f[v] + n - 2 * siz[u];
        solve(u, v);
    }
}
 
int main() {
    //cin >> n;
    scanf("%d", &n);
    for (int i = 0; i < n-1; i++) {
        int a, b;
        cin >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
     
    dep[0] = -1;
    dfs(1, 0);
     
    for (int i = 1; i <= n; i++) f[1] += dep[i];
    solve(1, 0);
     
    ans = 1 << 30;
    for (int i = 1; i <= n; i++) ans = min(ans, f[i]);
    //cout << ans << endl;
    printf("%d\n", ans);
    return 0;
}

Talk

题目

在这里插入图片描述

思路

随机游走模型,概率期望dp,手动解方程。

我们设 f i f_i fi为从位置 i i i到达最终位置的期望步数。可得转移方程如下:
f i = p ∗ f i + 1 + ( 1 − p ) ∗ f i − 1 ( 1 ) f_i=p*f_{i+1}+(1-p)*f_{i-1}(1) fi=pfi+1+(1p)fi11,这是没办法直接通过动态规划进行状态转移的,可以联立方程组高斯消元,但是复杂度较高。也可以直接手动解方程,线性时间复杂度,方法如下。

我们根据题目可知 f n = 0 f_n=0 fn=0,我们采用倒推。

换元做差,令 s [ i ] = f [ i ] − f [ i + 1 ] ( 2 ) s[i]=f[i]-f[i+1](2) s[i]=f[i]f[i+1]2,则可知答案为 ∑ i = 1 n s [ i ] \sum\limits_{i=1}^ns[i] i=1ns[i]
把(2)带入(1)可以得到 s [ i ] = ( 1 + ( 1 − p i ) ∗ s [ i − 1 ] ) / p i s[i]=(1+(1-p_i)*s[i-1])/p_i s[i]=(1+(1pi)s[i1])/pi,从而得到了 s i s_i si的递推关系,令 s [ 0 ] = 0 s[0]=0 s[0]=0,从第一项开始求即可。

#include <iostream>
using namespace std;
int main() {
    int n;
    scanf("%d", &n);
    double s = 0, ans = 0;
    for (int i = 1; i <= n; i++) {
        double p;
        scanf("%lf", &p);
        s = (1+(1-p)*s)/p;
        ans += s;
    }
    printf("%.3lf", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值