http://codeforces.com/problemset/problem/348/B

注意到如果顶点的数值确定了,那么它分下去的个数也就确定了,那么可以暴力枚举顶点的数值。

顶点的数值是和LCM相隔的,LCM就是,比如1有三个子节点,那么1的数值起码都是3的倍数,不然不能整除。

同理,1有三个儿子2、3、4、,如果3有三个儿子,那么1就要起码是9的倍数了,因为需要分给3的时候至少是3.

所以算出整颗树的LCM,叶子节点LCM是1,其他的LCM = lcm(所有子节点) * son[cur]

算出这个后,就可以暴力枚举顶点1的值了,每次枚举都dfs一次,有点暴力1700ms,学学正解先。

注意一点的就是LCM会爆LL,这个时候直接输出sum即可

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 1e5 + ;
int a[maxn];
LL sum;
struct Node {
int u, v, tonext;
}e[maxn * ];
int first[maxn], num;
void addEdge(int u, int v) {
++num;
e[num].u = u, e[num].v = v, e[num].tonext = first[u];
first[u] = num;
}
int vis[maxn], DFN = ;
int son[maxn];
void findSon(int cur) {
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v] == DFN) continue;
vis[v] = DFN;
son[cur]++;
findSon(v);
}
}
LL ans = 1e18L, tans;
LL LCM;
LL lcm(LL a, LL b) {
return a / __gcd(a, b) * b;
}
bool flag;
void dfs(int cur, LL val) {
if (flag) return;
if (son[cur] == ) {
if (val > a[cur]) {
flag = true;
return;
}
tans += a[cur] - val;
return;
}
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v] == DFN) continue;
vis[v] = DFN;
if (val % son[cur] != ) {
flag = true;
return;
}
dfs(v, val / son[cur]);
}
}
LL calc(int cur) {
if (son[cur] == ) return ;
LL thisLCM = ;
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v] == DFN) continue;
vis[v] = DFN;
thisLCM = lcm(thisLCM, calc(v));
}
if (thisLCM > sum / son[cur]) {
printf("%I64d\n", sum);
exit();
}
return son[cur] * thisLCM;
}
void work() {
int n;
scanf("%d", &n);
LCM = ;
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
sum += a[i];
}
for (int i = ; i <= n - ; ++i) {
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
vis[] = DFN;
findSon();
++DFN;
vis[] = DFN;
LCM = calc();
// cout << LCM << endl;
ans = sum;
sum /= LCM;
sum *= LCM;
for (LL i = sum; i >= LCM; i -= LCM) {
++DFN, tans = ;
flag = false;
// dfs(1, 24);
vis[] = DFN;
dfs(, i);
if (flag) continue;
printf("%I64d\n", ans - i);
return;
}
printf("%I64d\n", ans);
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}

因为已经知道根节点的值是LCM、2 * LCM、3 * LCM、..... sum中合法的最大的哪一个,那么可以二分答案。

一开始想把她们全部存入vector再二分,但是发现不用,直接二分id就行,就是二分LCM上面的那个倍数就可以了。

500ms

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 1e5 + ;
int a[maxn];
LL sum;
struct Node {
int u, v, tonext;
}e[maxn * ];
int first[maxn], num;
void addEdge(int u, int v) {
++num;
e[num].u = u, e[num].v = v, e[num].tonext = first[u];
first[u] = num;
}
int vis[maxn], DFN = ;
int son[maxn];
void findSon(int cur) {
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v] == DFN) continue;
vis[v] = DFN;
son[cur]++;
findSon(v);
}
}
LL ans = 1e18L, tans;
LL LCM;
LL lcm(LL a, LL b) {
return a / __gcd(a, b) * b;
}
bool flag;
void dfs(int cur, LL val) {
if (flag) return;
if (son[cur] == ) {
if (val > a[cur]) {
flag = true;
return;
}
tans += a[cur] - val;
return;
}
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v] == DFN) continue;
vis[v] = DFN;
if (val % son[cur] != ) {
flag = true;
return;
}
dfs(v, val / son[cur]);
}
}
LL calc(int cur) {
if (son[cur] == ) return ;
LL thisLCM = ;
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v] == DFN) continue;
vis[v] = DFN;
thisLCM = lcm(thisLCM, calc(v));
}
if (thisLCM > sum / son[cur]) {
printf("%I64d\n", sum);
exit();
}
return son[cur] * thisLCM;
}
void work() {
int n;
scanf("%d", &n);
LCM = ;
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
sum += a[i];
}
for (int i = ; i <= n - ; ++i) {
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
vis[] = DFN;
findSon();
++DFN;
vis[] = DFN;
LCM = calc();
// cout << LCM << endl;
ans = sum;
sum /= LCM;
sum *= LCM;
LL be = , en = sum / LCM;
while (be <= en) {
LL mid = ((be + en) >> );
++DFN, flag = false;
vis[] = DFN;
dfs(, mid * LCM);
if (flag) {
en = mid - ;
} else be = mid + ;
}
cout << ans - LCM * en << endl;
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}

B. Apple Tree 暴力 + 数学的更多相关文章

  1. cf202-div 1-B - Apple Tree:搜索,数论,树的遍历

      http://codeforces.com/contest/348/problem/B   B. Apple Tree time limit per test 2 seconds memory l ...

  2. POJ 2486 Apple Tree

    好抽象的树形DP......... Apple Tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6411 Accepte ...

  3. poj 3321:Apple Tree(树状数组,提高题)

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 18623   Accepted: 5629 Descr ...

  4. poj 3321 Apple Tree dfs序+线段树

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K       Description There is an apple tree outsid ...

  5. [poj3321]Apple Tree(dfs序+树状数组)

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 26762   Accepted: 7947 Descr ...

  6. POJ 3321 Apple Tree(树状数组)

                                                              Apple Tree Time Limit: 2000MS   Memory Lim ...

  7. 【HDU 4925】BUPT 2015 newbie practice #2 div2-C-HDU 4925 Apple Tree

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=102419#problem/C Description I’ve bought an or ...

  8. POJ 3321 Apple Tree(DFS序+线段树单点修改区间查询)

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 25904   Accepted: 7682 Descr ...

  9. URAL 1018 Binary Apple Tree(树DP)

    Let's imagine how apple tree looks in binary computer world. You're right, it looks just like a bina ...

随机推荐

  1. Eclipse jar打包详解

    通过Eclipse下的演示工程,介绍如何打包这样的项目:要导出的类里边用到了别的jar包. 方法/步骤     1. Eclipse下的演示工程结构如下图所示,其中Task.java是当前工程运行的M ...

  2. 百度API从经纬度坐标到地址的转换服务

    /// <summary> /// 百度API从经纬度坐标到地址的转换服务 /// </summary> /// <param name="lng"& ...

  3. oracle下 启动subversion命令 及 oracle相关服务启动备忘

    linux shell下  svnserve - d -r + 目录   例如:svnserve -d -r /svn 启动 svn服务. 访问svn://192.168.0.120/kjcg 测试. ...

  4. Building Objective-C static libraries with categories(ObjC、all_load、force_load)

    https://developer.apple.com/library/mac/qa/qa1490/_index.html    之所以使用该标志,和Objective-C的一个重要特性:类别(cat ...

  5. PHP多种序列化/反序列化的方法 json_encode json_decode

    序列化是将变量转换为可保存或传输的字符串的过程:反序列化就是在适当的时候把这个字符串再转化成原来的变量使用.这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性. 1. serialize和 ...

  6. Mina学习之---mina整体流程介绍

    现在公司使用的NIO框架一直时候Mina,当然这也的框架还有Netty.虽然一直在用,但只是简单的停留在业务层面,最近面试的时候有问Mina相关的东西.在之前的博客中已经对BIO,NIO,AIO这三种 ...

  7. Flutter实战视频-移动电商-63.购物车_详细页显示购物车商品数量

    63.购物车_详细页显示购物车商品数量 购物车的图标嵌套在statck组件里面 外层套了一个stack组件 数量我们需要用Provide 返回一个container来做样式 气泡效果,中间是个数字外面 ...

  8. Spring Boot2中配置HTTPS

    1.生成证书 使用jdk,jre中的keytool.exe生成自签名的证书,需要配置JAVA_HOME和path环境变量,即jdk的环境变量.命令如下: keytool -genkey -alias ...

  9. HDU - 1272 小希的迷宫 并查集判断无向环及连通问题 树的性质

    小希的迷宫 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一 ...

  10. E20181216-hm

    intersect vt. (指线条.道路等) 相交,交叉; vt. 横断,横切,横穿;