Codeforces Round #511 (Div. 1) C. Region Separation(dp + 数论)
题意
一棵 \(n\) 个点的树,每个点有权值 \(a_i\) 。你想砍树。
你可以砍任意次,每次你选择一些边断开,需要满足砍完后每个连通块的权值和是相等的。求有多少种砍树方案。
\(n \le 10^6, a_i \le 10^9\)
题解
先假设只砍一次。令所有点权和为 \(S\) ,那么假设要砍成 \(k\) 个连通块,则每个连通块的权值和均为 \(\displaystyle \frac{S}{k}\) 。
考虑如何得到砍的方案,以 \(1\) 号点为根 \(dfs\) ,若当前点 \(i\) 的子树之和 \(\frac{S}{k} | \displaystyle sum_i\) ,则当前子树可以砍下来。若最后恰好砍了 \(k\) 次,那么就得到了一个合法的砍树方案。
其实这就等价于 \(\displaystyle \sum_{i=1}^{n} [\frac{S}{k} | sum_i] = k\) 。
不难看出这个对应且仅对应一种方案。如果不足 \(k\) ,那么就没有那么多个点可以分;多于 \(k\) 的情况是不可能的,因为总和不够分配。
这个式子还不够优秀,我们转化一下:
[\frac{S}{k}|sum_i] &= [S | k \times sum_i] \\
&= [\frac{S}{\gcd(S,sum_i)}|k \times \frac{sum_i}{\gcd(S,sum_i)}] \\
&\because \frac{S}{\gcd(S,sum_i)} \bot \frac{sum_i}{\gcd(S,sum_i)} \\
&= [\frac{S}{\gcd(S,sum_i)} | k]
\end{align}
\]
然后就变成
\]
显然这个我们可以枚举倍数在 \(O(n \ln n)\) 的时间内解决(注意 \(k \le n\) )
那么如果砍多次呢?可以看出如果第一次砍成了 \(x\) 块,那么第二次砍成的块数 \(y\) 必须满足 \(x|y\) 。
因为你之后的权值只能比之前分的更多,且每个联通块的权值是之前的一个因子。
这部分也可以 \(O(n \ln n)\) 算。
总结
熟悉这种分成很多块有关于 \(O(\ln n)\) 复杂度的东西就行啦qwq
代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
typedef long long ll;
template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
}
void File() {
#ifdef zjp_shadow
freopen ("C.in", "r", stdin);
freopen ("C.out", "w", stdout);
#endif
}
const int N = 1e6 + 1e3;
bitset<N> pass;
ll sum[N], dp[N]; int n, fa[N];
int main () {
File();
n = read();
For (i, 1, n) sum[i] = read();
For (i, 2, n) fa[i] = read();
Fordown (i, n, 1) sum[fa[i]] += sum[i];
For (i, 1, n) {
ll tmp = sum[1] / __gcd(sum[1], sum[i]);
if (tmp <= n) ++ dp[tmp];
}
Fordown (i, n, 1) if (dp[i])
for (int j = i * 2; j <= n; j += i) dp[j] += dp[i];
For (i, 1, n)
pass[i] = (dp[i] == i && !(sum[1] % i)), dp[i] = 0;
dp[1] = pass[1];
ll ans = 0;
For (i, 1, n) if (pass[i]) {
for (int j = i * 2; j <= n; j += i)
if (pass[j]) dp[j] += dp[i];
ans += dp[i];
}
printf ("%lld\n", ans);
return 0;
}
Codeforces Round #511 (Div. 1) C. Region Separation(dp + 数论)的更多相关文章
- Codeforces Round #511 (Div. 2)
Codeforces Round #511 (Div. 2) #include <bits/stdc++.h> using namespace std; int n; int main() ...
- 2018.9.21 Codeforces Round #511(Div.2)
只写了AB,甚至还WA了一次A题,暴露了蒟蒻的本质=.= 感觉考的时候有好多正确或和正解有关的思路,但是就想不出具体的解法或者想的不够深(长)(怕不是过于鶸) 话说CF的E题怎么都这么清奇=.= A. ...
- Codeforces Round #174 (Div. 1) B. Cow Program(dp + 记忆化)
题目链接:http://codeforces.com/contest/283/problem/B 思路: dp[now][flag]表示现在在位置now,flag表示是接下来要做的步骤,然后根据题意记 ...
- Codeforces Round #511 (Div. 2):C. Enlarge GCD(数学)
C. Enlarge GCD 题目链接:https://codeforces.com/contest/1047/problem/C 题意: 给出n个数,然后你可以移除一些数.现在要求你移除最少的数,让 ...
- Codeforces Round #448 (Div. 2) A. Pizza Separation【前缀和/枚举/将圆(披萨)分为连续的两块使其差最小】
A. Pizza Separation time limit per test 1 second memory limit per test 256 megabytes input standard ...
- Codeforces Round #511 (Div. 2)-C - Enlarge GCD (素数筛)
传送门:http://codeforces.com/contest/1047/problem/C 题意: 给定n个数,问最少要去掉几个数,使得剩下的数gcd 大于原来n个数的gcd值. 思路: 自己一 ...
- Codeforces Round #511 Div.1 A Div.2 C
嗯切一题走人很开心. gzy-50分比我还惨. 题意:有n个数,去掉尽量少的数使得剩下数的gcd变大. 首先把这n个数都除以gcd,就变成了去掉尽量少的数使得gcd不等于1. 可以枚举一个质数,然后统 ...
- C. Enlarge GCD Codeforces Round #511 (Div. 2)【数学】
题目: Mr. F has nn positive integers, a1,a2,…,an. He thinks the greatest common divisor of these integ ...
- B. Cover Points Codeforces Round #511 (Div. 2)【数学】
题目: There are nn points on the plane, (x1,y1),(x2,y2),…,(xn,yn)(x1,y1),(x2,y2),…,(xn,yn). You need t ...
随机推荐
- pip3 升级失败的解决方法!亲测有效
pip3 --default-timeout=10000 install -U pip 注意:由于防火长城的存在,会导致更新失败,如果你加上--default-timeout=10000 这个就ok ...
- MySQL复制表的方式以及原理和流程
复制表的俩种方式: 第一.只复制表结构到新表 create table 新表 select * from 旧表 where 1=2 或者 create table 新表 like 旧表 第二.复制表结 ...
- 行政区划sql数据脚本
行政区划sql数据脚本 IF (EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TB_Province]') ...
- iOS开发 横向分页样式 可左右滑动或点击头部栏按钮进行页面切换
iOS开发 横向分页样式 可左右滑动或点击头部栏按钮进行页面切换 不多说直接上效果图和代码 1.设置RootViewController为一个导航试图控制器 // Copyright © 2016年 ...
- python_超级基础
初识计算机 CPU 计算机的大脑.中央处理单元,主要负责数据运算及计算,是运算计算中心. 存储器 内存 临时存储数据,供CPU运算使用. 优点: 读取速度快. 缺点: 容量小,成本高,断电即消失. 硬 ...
- rest-framework总结
1. CBV: pass 2 .APIView class BookView(APIView):pass url(r'^books/$', views.BookView.as_view(),name= ...
- PAT L3-010 是否完全二叉搜索树
https://pintia.cn/problem-sets/994805046380707840/problems/994805049870368768 将一系列给定数字顺序插入一个初始为空的二叉搜 ...
- Druid Monitor开启登录界面
<!-- druid --> <filter> <filter-name>druidWebStatFilter</filter-name> <fi ...
- JEECG DataGridColumn dictionary使用问题
<t:dgCol title="线索所属人" field="ownerId" query="true" queryMode=&q ...
- linux下jenkins的时区设置问题
https://blog.csdn.net/king_wang10086/article/details/76178711 [root@jenkins ~]# yum install -y ntpda ...