竞赛讨论区 > [题解]牛客练习赛24
头像
LittleFall
编辑于 2018-08-11 19:29
+ 关注

[题解]牛客练习赛24

好暴力,但ak了还是很开心.

A-石子阵列 组合数学

m(1000)种石子,每种无限个,从这些石子中取出n(1000)个,并按顺序排列起来,为了好看,相邻的石子不能相同。有多少种排列的方法,结果模1e9+7.

第一个石子有m种取法,第2~n个的限制是不能与前一个相同,有m-1种取法.
答案是$m*(m-1)^{n-1} \bmod 1000000007$

复杂度O(n),可以用快速幂优化.

int main(void)
{
    ll n=read()-1, m=read();
    ll ans = m;
    while(n--)
        ans = ans * (m-1) % MOD;
    cout << ans <<endl;
    return 0;
}

B-凤凰 树

给定一棵树,每个节点上有一只鸟,每秒钟每只鸟都可以从一个节点移动到相邻节点上,但每秒钟每条边只能承载一只鸟的飞行.问所有鸟移动到根节点(1号节点)所花的时间.

假设根节点只有一个孩子,那么答案就是总结点个数-1,也即这个以这个孩子为根的子树的节点个数,原因是这个子树与根节点只有一条边相连,每秒钟最多走一个,且每秒钟都可以走一个,因为每秒钟总会有至少一只鸟在子树的根处等待.
假设根节点有若干个孩子,可以发现以这些孩子为根的子树之间是互不影响的,所以答案就是以根节点的孩子为根的子树中最多的节点数目.

复杂度O(n)

vector<int> save[M];
int getnode(int n, int fa)
{
    int ret = 1;
    for(auto x : save[n])
        if(x != fa)
            ret += getnode(x, n);
    return ret;
}
int main(void)
{
    int n = read();
    for(int i = 1; i < n; i++)
    {
        int a = read(), b = read();
        save[a].push_back(b);
        save[b].push_back(a);
    }
    int ans = 0;
    for(auto x : save[1])
        ans = max(ans, getnode(x, 1));
    printf("%d\n", ans );
    return 0;
}

C-PH试纸 预处理答案

有一个长为n(1e6)的RB串,m(1e6)次询问,每次问第q个R或B字符出现在串中的第几个位置.

预先统计出所有的答案,对每个问题直接输出.复杂度O(n+m)

int rs[M], bs[M];
char tic[M];
int main(void)
{
    int n = read(), m = read();
    scanf("%s", tic);
    int rn = 0, bn = 0;
    for(int i = 0; tic[i]; i++)
        if(tic[i] == 'R')
            rs[++rn] = i + 1;
        else
            bs[++bn] = i + 1;
    char op[3];
    int t;
    while(m--)
    {
        scanf("%s %d", op, &t);
        if(op[0] == 'R')
            printf("%d\n", t <= rn ? rs[t] : -1 );
        else
            printf("%d\n", t <= bn ? bs[t] : -1 );
    }
    return 0;
}

D-插排树 树

一个n个节点的树,给出除根节点外所有节点的父亲及与父亲相连的边长,问所有节点距离根节点最远能有多远?

记忆化搜索一下,注意根节点不一定是1号点.复杂度O(n)

struct node
{
    int len;
    int all = -1;
    int fa = -1;
} save[M];
int getall(int id)
{
    return save[id].all == -1 
    ? save[id].all = save[id].len + getall(save[id].fa) 
    : save[id].all;
}
int main(void)
{
    int n = read();
    for(int i = 1; i < n; i++)
    {
        int id = read(), fa = read(), len = read();
        save[id].fa = fa;
        save[id].len = len;
    }
    for(int i = 1; i <= n; i++)
        if(save[i].fa == -1)
            save[i].all = 0;
    int ans = 0;
    for(int i = 1; i <= n; i++)
    {
        if(save[i].all == -1)
            getall(i);
        ans = max(ans, save[i].all);
    }
    printf("%d\n", ans );
    return 0;
}

E-青蛙 bfs

有一条路,路上有很多两个点之间的单向隧道,在每一个点可以选择:朝前走一个点,朝后走一个点,进入一个隧道(如果当前点有)并从隧道另一边出来,每个选择都花费一秒时间.问至少需要多少时间可以从起点走到终点.

bfs,dis[i]表示从起点最少走多少步可以走到这个点,用dis[i]是否为-1来表示是否访问过这个点.
因为一定能到达终点,每次循环时拿dis[m]是否为-1作为判断条件.

数据范围较小,每次直接遍历所有隧道,复杂度O(nm)
一个trick:数据有说隧道和终点不会出现在位置0,所以直接从1开始bfs,写朝前一步的时候更方便
int dis[M];
pair<int,int> trap[M];
int main(void)
{
    int m = read(), n = read();
    memset(dis, -1, sizeof(dis));
    dis[0] = 0, dis[1] = 1;
    for(int i = 0; i < n; i++)
    {
        trap[i].first = read();
        trap[i].second = read();
    }
    queue<int> q;
    q.push(1);
    while(dis[m] == -1)
    {
        int now = q.front();
        q.pop();
        for(int i = 0; i < n; i++)
        {
            if(trap[i].first == now && dis[trap[i].second] == -1)
            {
                dis[trap[i].second] = dis[now] + 1;
                q.push(trap[i].second);
            }
        }
        if(dis[now - 1] == -1)
        {
            dis[now - 1] = dis[now] + 1;
            q.push(now - 1);
        }
        if(dis[now + 1] == -1)
        {
            dis[now + 1] = dis[now] + 1;
            q.push(now + 1);
        }
    }
    printf("%d\n", dis[m] );
    return 0;
}

F-三轮 完全背包(非正解)

有n(50000)种商品,每种都有一个体积vi(50000),每种个数无限,给定一个m(50000),问组成1~m体积的方法总数.

遇事不决写暴力

完全背包求方案数,复杂度O(nm),牛客的评测机是真的好

int save[M], dp[M];
int main(void)
{
    int n = read(), m = read();
    for(int i = 1; i <= n; i++)
        save[i] = read();
    dp[0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = save[i]; j <= m; j++)
            dp[j] = (dp[j - save[i]] + dp[j]) % MOD;
    int ans = 0;
    for(int i = 1; i <= m; i++)
        ans = (ans + dp[i]) % MOD;
    printf("%d\n", ans );
    return 0;
}

全部评论

(1) 回帖
加载中...
话题 回帖

本文相关内容

等你来战

查看全部

热门推荐