Codeforces 1034C Region Separation - 数论 - 动态规划

题目传送门

  传送站I

  传送站II

  传送站III

题目大意

  给定一个$n$个点的树$T = (G, V)$,每个点有一个正整数点权$a_{i}$。整棵树是第1级划分。定义第$i$级划分是将第$i - 1$级划分中的每个区域划分成至少两个新的区域,并且所有区域都是一个连通块,每个点在每一级中只属于一个区域,在同一级划分内每个区域内的点的点权和相等。一种划分方案包含它划分的每一级。两种划分方案不同当且仅当它们划分的级数不同,或者存在一个点在某一级中它们在两种划分方案中属于不同区域。

  之前好像某次noip模拟考过类似的东西,但是当时没弄得清楚,感性理解了这个东西qwq。题解里涉及的大部分结论都被我猜到了,证这些花了半天,最后弃疗看题解。(为啥做了三道计数题都看了题解,果然我太菜了。)

注意

  以下结论都在这样一些限制条件下讨论:

  1. 点权均为正整数。
  2. 每个点只属于一个区域。
  3. 如果涉及到有根树相关,默认以1为根。

  设$s_{i}$表示以1为根时子树$i$内的点权和,$S = s_{1}$。

引理1 一棵$n$个点数的树,设$S = kS‘, k\in N_{+}, S‘ \in N$,则$\sum_{i = 1}^{n} [S‘\mid s_{i}] \leqslant k$

  证明 当$k = 1$的时候,因为$a_{1} > 0$,所以它的子树内的所有点的$s_{i} < k$。

  假设当$k \leqslant m - 1$时成立,考虑$k = m$的时候

  • 若树内不存在一个点$i$,使得$s_{i} = xS‘, x \in N\wedge 1\leqslant x < m$,则$\sum_{i = 1}^{n} [S‘\mid s_{i}] = 1$,显然成立。
  • 若树内存在一个点$i$,使得$s_{i} = xS‘, x \in N\wedge 1\leqslant x < m$,那么我们将它和它的父节点的边断开,把树分成两半部分,一半部分和为$xS‘$,另一部分和为$(m - x)S‘$。对于第一部分,它一定是以1为根的时候完整的一棵子树,把它删去后$i$的祖先的$s$值会减少,但是因为$S‘\mid s_{i}$,所以不会改变祖先的$s_{i}$对$S‘$取模后的剩余。因此可以将第一部分看成以$i$为根的树,第二部分看成以$1$为根的树,根据归纳假设易知,$\sum_{i = 1}^{n} [S‘\mid s_{i}] \leqslant m$。

  所以定理得证。

  不难发现,当$S‘$不是整数的时候,$\sum_{i = 1}^{n} [\frac{S‘}{s_{i}}\in Z] \leqslant k$也成立。因为我们将每个点的点权乘上$k$,这样新的$S‘$就是整数了,用引理1可得:

$\sum_{i = 1}^{n} [\frac{S‘}{s_{i}}\in Z] = \sum_{i = 1}^{n}[\frac{kS‘}{ks_{i}}\in Z]=\sum_{i = 1}^{n}[kS‘\mid ks_{i}]\leqslant k$

  对于一个树$T = (V, E)$,设$f(T, d) = \sum_{v_{i} \in V} [d\mid s_{v_{i}}]$。

定理2 一棵$n$个点数的树$T$,能将它划分成$k$个点权和相等的连通块的充分必要条件是:

  1. $k\mid S$
  2. $f(T, \frac{S}{k}) = k$

  证明 第一点的必要性显然,现在只考虑第二点。设$S = kS‘$。

  必要性 我们考虑$k$个连通块,每个连通块的最浅点的$s$值一定是$S‘$的倍数。因为假设它不是$S‘$的倍数,那么由第一点的必要性可知它的子树内不能划分成若干联通块,剩下的点会被孤立,这样会使得划分方式不合法。

  充分性 我们将所有满足$S‘ \mid s_{i}, i > 1$的点都和它的父节点把边断开,显然会产生$k$个连通块,现在证明这样一定满足条件:

    1. 因为点的权值都为正,所以不存在一个连通块的和为0或负数。
    2. 显然每个连通块的点权都是$S‘$的倍数
    3. 假设存在一个连通块的点权大于$S‘$,那么把它删去后会剩下若干个树$T_{1}, \cdots, T_{p}$,它们的点权和小于$(k - 1)S‘$,由引理1易证$\sum_{i = 1}^{p}f(T_{i}, S‘) < k - 1$。所以这个连通块内至少存在两个点它们的$s$值是$S‘$的倍数,这与构造的方案矛盾。所以不存在一个连通块的权值和大于$S‘$。

  由以上三点可知对于每一个连通块的权值都是$S‘$。因此定理得证。

  同时我们由证明过程也知道,满足$S‘ \mid s_{i}, i > 1$的点都必须和它的父节点把边断开,也就是说方案是唯一的。

  也就是说:

推论3 一棵$n$个点数的树$T$,能将它划分成$k$个点权和相等的连通块的方案数要么是0,要么是1。

  先考虑对于第2级划分,我们希望知道对于每一个$k, 1\leqslant k \leqslant n$,$f(T, \frac{S}{k})$的值。

  根据定义有

$f(T, \frac{S}{k}) = \sum_{v_{i} \in V} [\frac{S}{k}\mid s_{v_{i}}]\\= \sum_{v_{i} \in V} [S\mid s_{v_{i}}k]\\= \sum_{v_{i} \in V} [\frac{S}{(S, s_{i})}\mid k]$

  那么现在可以用一个简单dp在$O(n\log n)$内处理掉它。

  考虑级数大于2的时候,不难发现以下结论:

定理4 一棵$n$个点数的树$T$,能够划分成2个分别包含$k_{1}, k_{2}\ \ (k_{1} < k_{2})$个区域的级别的充分必要条件是:

  1. $k_{1}\mid k_{2}, k_{2}\mid S$
  2. $f(T, \frac{S}{k_1}) = k_1 \wedge f(T, \frac{S}{k_2}) = k_2$

  证明 必要性显然。

  充分性 考虑我们将这个数划分成$k_{1}$个区域,每个区域是一个连通块,那么就是一棵树。设它们分别是$T_{1}, \cdots, T_{k_{1}}$。每一部分的和都是$\frac{S}{k_{1}}$,由第一点可知是$\frac{S}{k_{2}}$的倍数,因此分开后对$s_{i}$对$\frac{S}{k_{2}}$取模后的剩余无影响。由引理1可知$f(T_{i}, \frac{S}{k_{2}}) \leqslant \frac{k_2}{k_1}$,又因为$f(T, \frac{S}{k_2}) = k_2 = k_{1}\times \frac{k_{2}}{k_{1}}$,所以$f(T_{i}, \frac{S}{k_{2}}) = \frac{k_2}{k_1}$,由定理2可知每一区域都可以划分成$\frac{k_{2}}{k_{1}}$个新区域。

  因此定理得证。

  由推论3和定理4可知如果将划分成$k$个区域的方案看成一个点,满足$k_{1}, k_{2}\ \ (k_{1} < k_{2})$和定理4的两点的两个合法的一级划分,那么$k_{1}$向$k_{2}$连一条有向边,显然它构成了一个DAG。那么一个合法的划分方案对应从1开始的一条路径。现在就简单了,用$g_{i}$表示以$i$为路径结尾的路径条数,再做一次dp就完了。

  最后来证一个可以压常数的结论,推广一下$f$,现在把它设成$f(T, d) = \sum_{v_{i} \in V} [\frac{s_{v_{i}}}{d} \in Z]$。

推论5 一棵$n$个点数的树$T$,设$S = kS‘, k\in N_{+}, k > 1, k\nmid S$,则$f(T, S‘) < k$

  证明 考虑$k = 2$的时候,因为$k\nmid S$,所以只有$s_{1}$满足条件,$f(T, S‘) = 1 < 2$。

  假设当$k \leqslant m - 1$的时候成立,考虑$k = m$的时候,

  • 若不存在一个点$i, i > 1$使得$\frac{s_{i}}{S‘} \in Z$,那么$f(T, S‘) = 1 < m$。
  • 若存在一个点$i, i > 1$使得$\frac{s_{i}}{S‘} \in Z$,那么我们把它和它的父节点的边断开,把树分成两棵树$T_{1}, T_{2}$,因为$\frac{s_{i}}{S‘}$的小数部分为0,所以对它的祖先$\frac{s_{j}}{S‘}$的小数部分没有影响,即不会改变它是否为整数。显然两部分的和都小于$mS‘$,所以由归纳假设可知当$k = m$时成立。

  因此定理得证。

  现在就不用判断$k$是否是$S$的约数了,只用判断$f(T, \frac{S}{k})$的值。

  总时间复杂度$O(n\log n)$。

Code

 1 /**
 2  * Codeforces
 3  * Problem#1034C
 4  * Accepted
 5  * Time: 717ms
 6  * Memory: 19900k
 7  */
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 typedef bool boolean;
16 #define ll long long
17
18 const int N = 1e6 + 5, M = 1e9 + 7;
19
20 ll gcd(ll a, ll b) {
21     return (b) ? (gcd(b, a % b)) : (a);
22 }
23
24 int add(int a, int b) {
25     return ((a += b) >= M) ? (a - M) : (a);
26 }
27
28 int n, res;
29 ll ss[N];
30 int fa[N], f[N], g[N];
31
32 int main() {
33     scanf("%d", &n);
34     for (int i = 1; i <= n; i++)
35         scanf(Auto, ss + i);
36     for (int i = 2; i <= n; i++)
37         scanf("%d", fa + i);
38     for (int i = n; i > 1; i--)
39         ss[fa[i]] += ss[i];
40     ll S = ss[1];
41     for (int i = 1; i <= n; i++)
42         if ((ss[i] = S / gcd(S, ss[i])) <= n)
43             f[ss[i]]++;
44     for (int i = n; i; i--)
45         for (int j = i << 1; j <= n; j += i)
46             f[j] += f[i];
47     g[1] = 1;
48     for (int i = 1; i <= n; i++)
49         if (f[i] == i) {
50             res = add(res, g[i]);
51             for (int j = i << 1; j <= n; j += i)
52                 g[j] = add(g[j], g[i]);
53         }
54     printf("%d\n", res);
55     return 0;
56 }

原文地址:https://www.cnblogs.com/yyf0309/p/9694235.html

时间: 2024-10-05 01:17:44

Codeforces 1034C Region Separation - 数论 - 动态规划的相关文章

Codeforces 413B Spyke Chatting(数论简单)

题目链接:Codeforces 413B Spyke Chatting 题目大意:n个人,m种聊天器,k次发送消息,然后给出n*m的矩阵,如果g[i][j]为1,则表示i号人会使用j号聊天器,接着给出k次消息发送者和聊天器,如果i在j种聊天器上发送了一条消息,那么所有使用j种聊天器的人都会接受到消息.现在要求每个人会接受到几条消息,自己发送的不算. 解题思路:分别记录每个聊天器上有多少个消息,以及每个人发送了多少条消息,然后计算每个人接受到多少条消息的时候只要将这个人所使用的各个聊天器消息数取和

[CodeForces - 1225C]p-binary 【数论】【二进制】

[CodeForces - 1225C]p-binary [数论][二进制] 题目描述 Time limit 2000 ms Memory limit 524288 kB Source Technocup 2020 - Elimination Round 2 Tags bitmasks brute force math *1600 Site https://codeforces.com/problemset/problem/1225/c 题面 Example Input1 24 0 Output

[Codeforces 1295E]Permutation Separation(线段树+贪心)

[Codeforces 1295E]Permutation Separation(线段树+贪心) 题面 给出一个排列\(p_1,p_2,...p_n\).初始时你需要选择一个位置把排列分成左右两个.然后在两个序列间移动元素使得左边序列的所有元素都比右边的所有元素小.给出每个元素\(p_i\)从一个序列移动到另一个序列的代价\(a_i\). 分析 显然最后得到的序列是小的数在一边,大的数在另一边.设从值为\(i\)的元素处分开之后移动代价为\(ans_i\). 一开始假设所有数都移到右边序列,那么

Codeforces 37D Lesson Timetable - 组合数学 - 动态规划

题目传送门 神奇的门I 神奇的门II 题目大意 有$n$组学生要上课2次课,有$m$个教室,编号为$1$到$m$.要确定有多少种不同的安排上课的教室的方案(每组学生都是本质不同的),使得它们满足: 每组学生第一次上课的教室的编号小于等于第二次上课的教室的编号. 第$i$间教室在第一次上课时,恰好有$x_{i}$组学生在场. 第$i$间教室在某次上课时,中间包含的学生组数不能超过$y_{i}$. 输出答案模$10^{9} + 7$. 因为第一次上课恰好有多少人,所以这个方案数是可以直接用组合数,暂

Codeforces 866C Gotta Go Fast - 动态规划 - 概率与期望 - 二分答案

You're trying to set the record on your favorite video game. The game consists of N levels, which must be completed sequentially in order to beat the game. You usually complete each level as fast as possible, but sometimes finish a level slower. Spec

ACM学习历程—HDU 3092 Least common multiple(数论 &amp;&amp; 动态规划 &amp;&amp; 大数)

hihoCoder挑战赛12 Description Partychen like to do mathematical problems. One day, when he was doing on a least common multiple(LCM) problem, he suddenly thought of a very interesting question: if given a number of S, and we divided S into some numbers

codeforces #271E Three Horses 数论

题目大意:有一种卡片,正面和背面各写着一个整数,可以用一个有序数对(x,y)表示 有三种操作: 1.出示一张卡片(x,y),获得一张卡片(x+1,y+1) 2.出示一张卡片(x,y)(x,y都是偶数),获得一张卡片(x2,y2) 3.出示两张卡片(x,y)和(y,z),获得一张卡片(x,z) 一个人想要卡片(1,a1),(1,a2),(1,a3),...,(1,an),他可以携带一张初始卡片(x,y)(1≤x<y≤m),求有多少种方案 首先我们发现: 第一个操作不改变y?x的值 第二个操作可以使

Codeforces 762A k-th divisor(数论)

题目链接:k-th divisor 直接暴力-- 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i,a,b) for(int i(a); i <= (b); ++i) 6 #define LL long long 7 8 LL n, k, h, ans; 9 int num; 10 11 int main(){ 12 13 scanf("%lld%lld", &n, &a

Codeforces 622F 「数学数论」「数学规律」

题意: 给定n和k,求 1 ≤ n ≤ 109, 0 ≤ k ≤ 106 思路: 题目中给的提示是对于给定的k我们可以求出一个最高次为k+1的关于n的通项公式. 根据拉格郎日插值法,我们可以通过k+2个离散的点来确定这个通项.所以求出前k+2项,然后就可以确定公式. 拉格郎日差值法传送门:http://www.guokr.com/post/456777/ 最后得出的公式是酱紫的:(公式来自卿学姐博客) 然后问题来了,有除法如何搞定模运算...这个就用到逆元的运算了,逆元的定义就是大家都学过的离散