B. Apple Tree 暴力 + 数学
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 暴力 + 数学的更多相关文章
- cf202-div 1-B - Apple Tree:搜索,数论,树的遍历
http://codeforces.com/contest/348/problem/B B. Apple Tree time limit per test 2 seconds memory l ...
- POJ 2486 Apple Tree
好抽象的树形DP......... Apple Tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6411 Accepte ...
- poj 3321:Apple Tree(树状数组,提高题)
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 18623 Accepted: 5629 Descr ...
- poj 3321 Apple Tree dfs序+线段树
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Description There is an apple tree outsid ...
- [poj3321]Apple Tree(dfs序+树状数组)
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 26762 Accepted: 7947 Descr ...
- POJ 3321 Apple Tree(树状数组)
Apple Tree Time Limit: 2000MS Memory Lim ...
- 【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 ...
- POJ 3321 Apple Tree(DFS序+线段树单点修改区间查询)
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 25904 Accepted: 7682 Descr ...
- 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 ...
随机推荐
- div遮罩弹框口
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- hdu-5744 Keep On Movin(思维)
题目链接: Keep On Movin Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Oth ...
- hdu-5621 KK's Point(dp+数学)
题目链接: KK's Point Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...
- Python:循环
循环语句:while循环,for循环 例1:求1-100的所有数的和 n = 100 sum = 0 count = 1 while count <= n: sum = sum + count ...
- ubuntu166.04之Caffe安装
写在前面:之前一直在搞keras,最近由于某些需求,需要学习caffe,在此记录caffe的安装记录.默认已经安装了cuda 如果是从其他的深度学习平台迁移到Caffe,那么按照这个教程来就可以了. ...
- VC6.0 快捷键
F1: 帮助 Ctrl+O :OpenCtrl+P :PrintCtrl+N :NewCtrl+Shift+F2 :清除所有书签F2 :上一个书签Shift+F2 :上一个书签Alt ...
- bzoj 2836 魔法树——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2836 树剖裸题.然而WA.RE了好久…… 原来是跳 top 的那个地方! top 不相等的时 ...
- 【Boost】boost库asio详解2——io_service::run函数无任务时退出的问题
io_service::work类可以使io_service::run函数在没有任务的时候仍然不返回,直至work对象被销毁. void test_asio_nowork() { boost::asi ...
- fragment error
error: android.view.InflateException: Binary XML file line #6: Error inflating class fragment 解决办法 ...
- project工期出现小数问题
进入“选项”,点击“日程”,将默认“开始”.“结束”时间调整为“9点~18点.原为PREJECT 日历 (注意是日历~!!)默认的“8点~17点”,与preject系统默认时间“9点~18点”有差别~ ...