ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

2021“MINIEYE杯”中国大学生算法设计超级联赛 第四场题解

2021-07-29 22:02:09  阅读:381  来源: 互联网

标签:第四场 cur fa int 题解 ai 2021 权值 now


2021“MINIEYE杯”中国大学生算法设计超级联赛   第四场题解

第一题傻瓜题卡了两小时?

6986 Kanade Loves Maze Designing

题意:

给定一棵树,树上每个点的编号从1  - N,然后每个点有一个值。

现在要你从树上每一个点出发,到其他点,然后带入到该函数中求函数值......

有点绕,我们打个比方:

比如现在我们从第 i 个点出发,显然轮到遍历第 j 个点了,函数中 ai,j 代表的就是从i -> j我能拿去不同权值的数量

比如下面这样一棵树

其中:

1 -> 1

2 -> 1

3 -> 4

4 -> 5

5 -> 1

6 -> 4

以上是各个点的权值

那么我们从1 -> 2的ai,j就是1,因为只能拿到1这个种类的数

但是我们从1 -> 4的ai,j就是2,因为我们能拿到1和5这两个数

知道了这个ai,j是怎么回事,下一步就是怎么算?

由于是从一个点出发,我们需要遍历整个图,然后对于一棵树我们可以知道如下性质:

每两点之间的路径有且只有一条(如果不重复经过一条边的话)

那么其实我们从一个节点出发,遍历一遍这个树,就能得到ai,j的值了

具体DFS代码如下:

点击查看代码
void dfs(int cur,int fa)
{
    if(!cn[c[cur]])
    now[cur] = now[fa] + 1;
    else
    now[cur] = now[fa];
    
    cn[c[cur]] += 1;
    for(int i = head[cur];i;i = a[i].ne)
    {
        int to = a[i].to;
        if(to != fa)
        dfs(to,cur);
    }
    cn[c[cur]] -= 1;
}

简单解释一下:

从cur点出发,如果当前点的权值是第一次遍历得到,那么就相当于是在父亲结点的a i , j基础上+1

否则就是父亲结点的值

然后记录一下这个权值。

后面我们退出当前节点时需要将此权值回溯,也就是 - 1操作~

完整代码:

点击查看代码
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 2000 + 7;
const int MOD1 = 1e9 + 7;
const int MOD2 = 1e9 + 9;
typedef long long ll;
struct node
{
    int ne,to;
    int w;
}a[MAXN<<2];
int head[MAXN],cnt;
void add(int x,int y,int w = 0)
{
    a[++cnt].ne = head[x];
    head[x] = cnt;
    a[cnt].to = y;
    a[cnt].w = w;
}
ll c[MAXN];
ll pw1[MAXN],pw2[MAXN];
void ini()
{
    pw1[0] = pw2[0] = 1;
    for(int i = 1;i < MAXN;i++)
    {
        pw1[i] = pw1[i - 1]*19560929%MOD1;
        pw2[i] = pw2[i - 1]*19560929%MOD2;
    }
}
ll now[MAXN];
ll cn[MAXN];
void dfs(int cur,int fa)
{
    if(!cn[c[cur]])
    now[cur] = now[fa] + 1;
    else
    now[cur] = now[fa];
    
    cn[c[cur]] += 1;
    for(int i = head[cur];i;i = a[i].ne)
    {
        int to = a[i].to;
        if(to != fa)
        dfs(to,cur);
    }
    cn[c[cur]] -= 1;
}
int main()
{
    int t;
    ini();
//    ll ans = 0;
//    int b[6] = {1,1,2,2,1,2};
//    for(int i = 0;i < 6;i++)
//    {
//        ans = ans + b[i]*pw1[i]%MOD1;
//        ans %= MOD1;
//    }
//    cout<<ans;
//    return 0;
    scanf("%d",&t);
    while(t--)
    {
        for(int i = 1;i <= cnt;i++)
        head[i] = 0;
        cnt = 0;
        
        int n;
        scanf("%d",&n);
        for(int i = 2;i <= n;++i)
        {
            int x;
            scanf("%d",&x);
            add(x,i);
            add(i,x);
        }
        for(int i = 1;i <= n;++i)    scanf("%lld",&c[i]);
        for(int i = 1;i <= n;++i)
        {
            now[i] = 0;
            dfs(i,i);
            ll ans1 = 0,ans2 = 0;
            for(int j = 1;j <= n;++j)
            {
                ans1 = ans1 + now[j]*pw1[j - 1]%MOD1;
                ans1 %= MOD1;
                ans2 = ans2 + now[j]*pw2[j - 1]%MOD2;
                ans2 %= MOD2;
            }
            printf("%lld %lld\n",ans1,ans2);
        }
    }
    return 0;
}

6992 Lawn of the Dead

两场连续的比赛都有从1,1出发到N,M,而且每次都是往右或者往下走的这种题,还是不会,真彩

题意:

给你一个僵尸,开始在(1,1),只能往右走和往下走,然后有些地方有雷,问你僵尸可以访问的节点数量

思路:

首先我们非常容易得到一个结论,那就是

第一行出现的第一个禁区之后的所有点我们都不能走到

嗯,然后就没有然后了

后面的情况会有些复杂,dalao们觉得简单当我没说QAQ

我们思考一下这样一个问题:

对于一行一段连续的区间,什么情况下我们才能走这段区间的点呢?

看下面的图~

标签:第四场,cur,fa,int,题解,ai,2021,权值,now
来源: https://www.cnblogs.com/rhmemory/p/15077280.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有