您的位置:首页 > 大数据 > 人工智能

2017 Multi-University Training Contest 第一场

2017-07-27 11:04 337 查看
题解在:http://bestcoder.hdu.edu.cn/blog/2017-multi-university-training-contest-8-solutions-by-%E5%8C%97%E4%BA%AC%E8%88%AA%E7%A9%BA%E8%88%AA%E5%A4%A9%E5%A4%A7%E5%AD%A6/#comment-42

四题200多名吧

反正就只能切水题

1001

求2^m次方有多少位,一开始以为是找规律,但发现有误差,后来发现用公式变成log可以直接算出来。

1002

很坑,wa了很多次。但是思路一开始就是对了,算出各个字母的贡献值,然后排序,不过一开始没注意前导0

1006

置换群,然后xzn写完,帮他查了很多弱智错误。。然后过了

1011

找规律 我们可以发现是 (n 1 2 3 4 … ..n-2) + (n-1 1 2 3 ….n-2)的循环节。

然后敲了一发,就过了。

补题:

1003

题意:一棵树中每个节点都有一个颜色,求所有路径的sum。

每条路径值 = 这条路径经过的颜色种数。

这个问题的路径其实是可以分割的,比赛时一直以为不可以分割,所以不会。

既然可以分割,必然也不需要去枚举路径。

比如

1

\

2

\

3

这样一棵树,颜色1 经过他的路径条数有2条

颜色2 经过他的路径条数有3条

颜色3经过他的路径条数有2条 所以ans=7

1

\

2

/ \

1 3

这样一棵树,颜色1 经过他的路径条数有2+3条

颜色2 经过他的路径条数有3+3条

颜色3经过他的路径条数有2+1条 所以ans=14

我们可以再列举几个例子,仔细想想,这个推断竟然是成立的,惊了!

再仔细想想,其实是有道理的,因为每条路径上的每种颜色对答案的贡献值其实是1

所以对于每一种颜色来说,贡献值就是有多少条路径通过这一种颜色。

但是统计这个是很有可能重复统计的,所以我们反过来思考,有多少条路径没有经过某种颜色

然后我们跑出dfs序 每一种颜色(可能有多个点) 会把树 划分成许多块。

然后我们那总路径数,减去这些不经过这种颜色的路径数。

然后我们再看标程,哇,写的是真的好,这是世界上最难学的算法就是dfs。

typedef long long LL;
const int maxn = 200001;
int n, c[maxn], lnk[maxn], pos[maxn], ctr[maxn], rem[maxn];

//rem 存的是 当前节点所有子节点数 (当某颜色上面的节点没有当前颜色节点时,上面的所有节点块形成的每条路径不不经过这种颜色。

//ctr  存在的是下一个相同颜色节点 的 子节点个数。

LL ans;
struct Edge {
int nxt, v;
} e[maxn << 1 | 1];
inline LL sum2(int x) {
return (x * (x - 1LL)) >> 1;
}
int dfs(int u, int fa) {
int su = 1, o = pos[c[u]];  // pos[c[u]] 当前颜色在dfs中上一个当前颜色的节点号
pos[c[u]] = u; // 颜色x的位置更新为u,当前的
for(int it = lnk[u]; it; it = e[it].nxt)  // 遍历
if(e[it].v != fa) {
ctr[u] = 0;        // ctr 要初始化为0,不然dfs与u相同的颜色时会累加到ctr[u]上来
int sv = dfs(e[it].v, u);  // e[it].v这一块子树的节点数。不包括u
ans -= sum2(sv - ctr[u]);  //(e[it].v这一块子树)所有子节点数-下一个相同颜色节点的子节点数= 他们之间的连通块的数目。
//  还有一个忽略的地方: 如果ctr[u]=0,那么说明下面没有相同颜色,所以下面的块形成的路径也应该减去。
su += sv;
}
//    (o ? ctr[o] : rem[c[u]]) += su;
/* 走到这一步时,dfs已经把u的所有的子树都扫过一遍了。
如果o为真,代表前面最近出现c[u],节点号为o,且o 不可能是子树中出现的
所以此时,当前节点 的所有子节点数(包括自己) 都加到 上一个节点o的ctr 中
*/
if(o) ctr[o]+=su;    //
else rem[c[u]]+=su;  //如果上面没出现过, 那么他所有的子树放进rem[当前颜色](把自己也放进去)
pos[c[u]] = o;   // 还原当前颜色的节点号,所以每一个的o 都必然是上面最近的颜色x的位置。
return su;   //返回包括自己+所有子树的节点数
}
int main() {
//freopen("1.txt","r",stdin);
for(int Case = 1; scanf("%d", &n) == 1; ++Case) {
for(int i = 1; i <= n; ++i) {
scanf("%d", c + i);
lnk[i] = rem[i] = 0;
}
for(int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
e[i << 1] = (Edge){lnk[u], v};
lnk[u] = i << 1;
e[i << 1 | 1] = (Edge){lnk[v], u};
lnk[v] = i << 1 | 1;    // 链式存图
}
ans = sum2(n) * n; // 一共有n(n-1)/2条路径,假设每条路径都经过n?
//        printf("%I64d\n",ans);
dfs(1, -1);
//        printf("%I64d\n",ans);
for(int i = 1; i <= n; ++i)  // 遍历所有节点
ans -= sum2(n - rem[i]);
printf("Case #%d: %I64d\n", Case, ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  2017多校
相关文章推荐