[CERC2017]Gambling Guide
设 (f_u) 表示 (u) 到 (n) 的期望。
(f_n=0)
这个东西满足堆优化 (Dijkstra) 的贪心策略,所以就堆优化 (Dijkstra) 即可。
TopCoder SRM489Div1:AppleTree
可以先算出满足要求至少要多长,假设长度为 (L),那么剩下的 (d-L) 可以任意插入,这样就可以直接计算答案了。
考虑怎么算长度,将 (r) 从小到大放入,显然后面的一定满足前面的限制。
设 (f_{i,j,k}) 表示插入到了第 (i) 个数,有 (j) 个空需要插入,总长度为 (k) 的方案数。
每次插入一个数字就看插到中间或者两边,可以选择插入之后不计算贡献(表示新建空给后面的插入),如果不新建空就计算长度贡献。
Atcoder ARC071 F:Infinite Sequence
可以发现,如果有连续的两个数字都大于 (1),那么后面的数字都是一样的。
设 (f_i) 表示前 (i) 个位置的答案(当前位置的数不确定),每次可以写一个 (1),或者放一个 (x(x>1)) 和 (x) 个 (1),可以前缀和优化。
每次的 (f_i) 贡献答案,可以枚举填两个大于 (1) 的,或者填一个大于等于剩下长度的。
注意特判 (f_i,i=n) 时候的贡献。
Atcoder AGC013 D:Piling Up
可以发现,如果直接设 (f_{i,j}) 表示前 (i) 轮,还有 (j) 个黑球的方案数,最后的序列会计算重复。
考虑怎么样子才会计算重复,也就是黑球的变化曲线通过上下平移可以重合。
不难同一种方案的曲线中一定会有一条的最小值为 (0)。
所以强制在最小值为 (0) 的时候计算即可。状态里面多加一维 (0/1) 表示是否经过 (0) 即可。
Atcoder ARC073 F:Many Moves
肯定是两个点交叉走,每次走一个区间。
直接在区间的端点处转移过来,每次贡献为区间长度内的走的代价和另一个点跳过来的代价。
这个显然可以两棵权值线段树维护。
Codeforces 1082 F:Speed Dial
(trie) 树上选择 (k) 个点即可,简单树形 (DP)。
Codeforces 1103 D:Professional layer
答案只和 (d) 的质因子有关,所以 (a) 除掉多余的质数,显然最多选择 (11) 个数,每个数字删除 (d) 的质因子的一个子集。
那么可以设计出一个简单的状压的子集 (DP),然后对于除掉多余的质数相同的肯定选择前 (11) 小就好了。
并且一个状态 (S),最多只能从小到大转移 (11) 次,然后复杂度就卡入 (20s) 了,由于非常不满,所以实际上非常的快。
Atcoder ARC073 E:Ball Coloring
分两种情况:
一个是最大值和最小值不在一边,那么直接比较 (x,y) 贪心分配即可。
当最大值和最小值在一边的时候,按照 (x) 排序,枚举最小值,然后反转前缀的 (x,y) 即可。
[ZJOI2012]波浪
只要按照从小到大的顺序插入所有数就行了。
设 (f[i][j][k][l]) 表示插入 (i) 个数,当前序列波动值为 (j),序列现在被分为 (k) 个连续的段,序列边界的状态为 (l) ,(l) 为 (0) 表示边界没有数,为 (1) 表示边界有一个数,为 (2) 表示边界有两个数。
Atcoder AGC030 F:Permutation and Minimum
考虑从大到小加入数字,把 (2n) 个位置分成 (n) 组。
那么可以设计状态 (f_{i,j,k}) 表示从大到小的第 (i) 个位置,有 (j) 个已经知道位置并且有一个未知的个数,(k) 个不知道位置并且有一个未知的个数。
然后转移即可,最后乘上两个都未知的个数的阶乘。
Codeforces 809C:Find a car
转化成左上角矩阵的求和,数位 (DP),设 (f_{i,0/1,0/1,0/1}) 表示 (i) 位,三个限制是否到达危险态,记录和和方案数即可。
Codeforces 908G:New Year and Original Order
假设第 (i) 位填 (3), 那么他的贡献的 (3 imes 10^i),考虑把这个贡献拆开。
比如:(3ge3,3ge2,3ge1) 我们在这一位填 (1,2,3) 时都记上 (10^i) 的贡献。
设 (f_{i,j,k,l}) 表示前 (i) 个位置,有 (j) 个位置的数字大于等于 (k),(l) 表示是否为安全态。
直接转移即可。
Codeforces 799E:Aquarium decoration
按照两个人喜欢的状态分成 (4) 类。
首先每一类选的东西肯定是排序之后的一个前缀。
枚举两个都喜欢的选择多少个,贪心选只有一个喜欢的,剩下的选择前 (k) 小即可。
TopCoder SRM502Div1:TheCowDivOne
考虑容斥,枚举最后一个数出现的次数 (i)。
那么可以发现前面 (k-i) 个数的取值必须是 (gcd(n,i)) 的倍数,不然肯定没有解。
考虑最后这个数的取值有哪一些,当固定前 (k-i) 个数的和的时候,最后这个数字显然可以取出 (gcd(n,i)) 种值。
设 (f_{i,j}) 表示 ([0,n-1]) 取出 (j) 个,和为 (i) 的倍数的方案数。
那么
(n/p) 表示最后一个数在整个 ([0,n-1]) 的取值。
注意到我们要选取的集合是无序的,而任何一个数都可以成为最后一个数,那么最后要除掉 (k)。
考虑这样的状态数,(f_{i,j}) 被访问当且仅当 (i|n,i|(k-j))。
状态数就是 (sum_{i}[i|n]frac{k}{i}) 级别的,即 (kln k),总复杂度就是 (O(k^2lnk))。
POJ1149:PIGS
网络流。
源点向每个猪圈连边,容量为猪的个数。
按照人分层,上一层的点向一层分配,并向汇点连边,容量为每个人的上界。
Codeforces 434D:Nanami's Power Plant
把费用取反之后转化为最小费用的模型,注意到 (l_i,r_i) 都很小,很容易可以转化成“HNOI切糕”的模型。
每个点建立 (r_i-l_i+2) 个点,相邻两个点 ((x-1,x)) 之间连边 (-(a_ix^2+b_ix+c_i))。
然后对于限制 ((u,v,d)),就直接 (u) 的 (x) 号点向 (v) 的 (x-d) 号点连边 (inf) 即可。
最后跑一遍最小割,由于流量不能是负,就给每个点的边加上一个大于所有权值的极大值 (A) 即可。
答案就是 (nA-mincut)。
BZOJ4501:旅行
设 (f_u) 表示 (u) 到 (n) 的最小期望,(d_u) 为出度,(suf_u) 为出边集合,那么
可以选择删掉一些出边,考虑分数规划。
分数规划完之后,由于有删除 (y) 就必须删除 (x),即选 (x) 就必须选 (y) 的限制,所以求一个最大权闭合子图即可。
Codeforces 802C:Heidi and Library
费用流。
首先可以拆点,(i,i+n) 连 (-inf),表示必须选。
对于 (i,j) 两天,如果 (a_i
e a_j) 那么连 (i+n,j) 边权为 (c_{a_j}),否则边权为 (0)。
这样就只要选出覆盖所有 (i,i+n) 的路径,权值和最小就好了。
由于最开始强制了 (i,i+n) 连 (-inf),所以每一次增广必定覆盖所有 (i,i+n) 的路径。
因此根据费用流的性质,只需要当代价不会更小的时候结束增广即可。
[ZJOI2011]营救皮卡丘
费用流。
类似上面的建图,预处理出 (f_{i,j}) 表示 (i) 到 (j) 不经过大于 (j) 的点的最短路。
(i+n) 向 (j) 连 (f_{i,j}) 代价的边即可。
TopCoder SRM570Div1:CurvyonRails
费用流。
对于这种网格肯定要想到黑白染色。
考虑如果没有直线的代价怎么求是否有合法方案。
那么就是每个点入度等于出度,由于黑白染色了,所以可以令黑点入流量为 (2),白点出流量为 (2),相邻的连边网络流出解。
现在有直线的代价,考虑把一个点分出两个点出来,分别表示上下和左右。
选了两次上下或者两次左右的时候有额外代价。
直接连两条边,一条费用 (0),一条 (1)。因为费用流的性质,所以肯定会先走 (0) 边。
BZOJ3691:游行
费用流。
首先可以把额外代价看成是没有入边的点贡献,这样就可以建图,((i,j+n)) 费用为最短路。
或者 ((i+n,i)) 容量为 (infty),只连接原图中有边的 ((i,j+n))。
现在的问题是多组询问的 (C)。
根据费用流增广的性质,存在一个增广的时刻,使得之前每次增广的代价小于等于 (C),之后大于 (C)。
那么二分这个分界点就好了。
Codeforces 671D:Roads in Yusland
线性规划问题的对偶问题转化:(max{c^Tx|Axle b} = min{b^Ty|A^Tyge c})
放到这个题目转化就变成了:选最多的边(可以重复),使得每个人的覆盖的边不超过 (c_i) 条。
这个东西就从深到浅贪心就好了,可并堆维护即可。
CodeChef:Ski Resort
一条路径 (p_1,p_2,...,p_k) 不合法当且仅当 (exists i < k, p_i < p_{i+1})。
那么显然可以转化为求 (S) 和 (T) 的最小割。每个点向小于等于它的点连边即可。
而由于如果同时两个点割了出点同样的边,显然只要增加到两个点的最大值就好了,但是我们割了两次,于是就假了。
所以可以把一个点拆成 (5) 个点,把周围的点按照高度小到大排序。
周围的点依次连边这个点拆成的相邻的点,边权为 (inf)。
这个点相邻的点依次连高度对应的代价。
可以发现,每个点拆成的点如果割掉了后面的边然后再割前面的一定不优,保证了正确性。
Codeforces GYM 101194 J:Mr.Panda and TubeMaster
容易发现是费用流。然后套一个“CTT2017无限之环”发现并不可以,不仅不好限制直线,而且难以处理每个点可以选或不选。
考虑给每一个点钦定一个出边,拆点。
一个比较奇怪的做法就是:先黑白染色,让黑点只考虑上下连边,白点只考虑左右。
这样下来,只需要每个点直接连边就能解决每个点必须选择的问题了。
然后考虑怎么样实现每个点可以选或不选,其实只要自己匹配自己就好了。
最后实际上只要跑一遍二分图最大权匹配就好了。
[CEOI2008]Fence
没想到 111 和 20 居然不是乱给的。。。
首先 (20 imes 3 < 111) 如果能围住就尽量围住(围住的最小单位显然是 (3))。
不能围住的先不管,那么就是对能围住的找到一个最小的环。
枚举每一条向量看是否能围住(都在内侧),然后 (floyed) 找最小环即可。
[HAOI2011]防线修建
就是动态删除,要求上凸壳的长度。
倒过来变成动态加入,用平衡树(set)维护凸壳即可。
[SCOI2015]小凸想跑步
求出第一条边和每一条边的限制,这是一个线性规划的形式,半平面交求出可行域即可。
[SDOI2013]逃考
求出泰森多边形,然后连边即可。
枚举每一个点,求出它和每个点的中垂线,这样求出半平面交就可以求出这个点管辖的范围,然后与外面的点连边,最后 (BFS) 即可。
Geometry_Widget真好用。
Codeforces 718C:Sasha and Array
矩阵乘法满足结合律,所以就线段树维护矩阵即可。
[FJOI2016]神秘数
考虑从小到大加入数字,假设前面能够凑到 (x),如果新的数 (v le x+1),那么能凑出的数变成 (x+v),不难发现只要每一次加入 (le x+1) 就好了。主席树维护。
由于每两次一定翻倍,那么就是两只 (log)。
51NOD 1685:第K大区间2
二分答案,然后询问满足的奇数区间的该个数。
Codeforces 715C:Digit Tree
点分治,因为 (10^d) 和 (m) 互质,所以存在逆元,(map) 查询即可。
Codeforces 833D:Red-Black Cobweb
按照套路,首先点分治。
那么就是要求满足以下条件的路径的权值的乘积。
(egin{cases}
2(b_1+b_2) ge w_1+w_2\
2(w_1+w_2) ge b_1+b_2
end{cases}
)
由于点是无序的,又不能直接求二次剩余,所以不太好做,直接求可以用 (CDQ) 分治解三维偏序,套上点分治,三只 (log)。
仔细观察这个东西,不合法的条件有两个,但是实际上一个满足,另一个一定不满足,所以求解不合法即可,二维偏序,树形数组实现。
BZOJ4548:小奇的糖果
枚举下边界,向上扫描,每一次删除点。合法的线段一定是相邻两个同色点卡着的,每次合并一下即可。
树形数组+链表维护。
POJ3718:Facer's Chocolate Dream
显然答案只跟 (1) 的个数有关,那么可以设 (f_{i,j}) 表示选了 (i) 个,有 (j) 个位置为 (1) 的方案数。
因为 (v) 个 (1) 可以任意组合,我们再除以一个组合数 (inom{n}{v}) 就是答案。
假设选出的 (m) 个数不同顺序算是不同的方案,求出来以后再除以一个 (m!) 就可以了。
这样就好做了,直接 (DP) 即可。四种情况。
但是并没有考虑第 (i) 个数与之前的 (i−1) 个数重复的情况,所以要减去。
减去的方案数就是 (f_{i-2,j}inom{n}{3}(i-1))
POJ1845:Sumdiv
按照公式计算即可。注意判断是 (9901) 倍数的情况。
牛客Wannafly挑战赛25 A:因子
每个质因子分别考虑即可。
LOJ530:「LibreOJ β Round #5」最小倍数
(n!) 中质数 (k) 有 (sum_{i}lfloorfrac{n}{k^i}
floor) 个。相当于是将 (n) 转化成 (k) 进制后,设第 (i) 位的值位 (v),那么就有 ((v ... . vv)_{k}) 的贡献。
预处理一下前缀和之类的就可以算出每个 (k) 对应的 (n),最后取个 (max) 就好了。
BZOJ3309:DZY Loves Math
考虑计算 (g(d)=sum_{i|d}f(i)mu(frac{d}{i}))
这个东西可以看成是枚举 (d) 的质因子集合,钦定这些集合的指数减 (1),然后对于所有的指数的 (max) 的和。
那么就很好做了。
如果质因子集合的指数都是 (a),那么只有一种情况为 (max=a-1),其它的情况都是 (max=a),这些贡献之间两两抵消,设质因子的个数为 (k),那么会剩下一个 (-(-1)^{k})。
如果质因子集合的指数不都是 (a),那么只有两种情况,一种是 (max=max{a}),一种是 (max=max{a}-1),两种情况的方案数都是偶数,同种方案的贡献两两抵消,最后剩下 (0)。
所以只要求出那些质因子集合的指数相同的数的贡献就好了。
可以发现有值的 (g),设为 (g(x^a))((a) 为相同的指数),那么 (g(x^a)=-mu(x))
所以可以直接枚举 (mu) 筛出 (g),复杂度显然是线性的。
用上面的方法配上杜教筛应该是可以做到 (a,ble 10^9) 级别的询问的,枚举那个 (a) 筛 (mu) 的前缀和就行了(大概)。
BZOJ3561:DZY Loves Math VI
不妨假设 (nle m),爆推:
枚举 (d),预处理自然数幂和(显然不用快速幂)暴力计算即可,复杂度为调和级数,(O(nlnn))。
BZOJ3601:一个人的数论
爆推:
这玩意儿前面是一个狄利克雷卷积,后面突然出现了一个自然数幂和就很难受。
而众所周知,自然数幂和 (sum_{i=1}^{n}i^d) 是一个关于 (n) 的 (d+1) 次数多项式。
运用高斯消元或者拉格朗日插值等方法不难得到这个多项式 (f(x)),那么答案就可以写成 (sum_{g|n}mu(g)g^df(frac{n}{d}))。
可以发现,多项式的每一项都是一个 ((frac{n}{d})^ka_k)((a) 为系数)的形式,不考虑系数,则这显然是一个积性函数。
因此,只要枚举多项式的幂次,然后对于每一个质因子 (p_i^{a_i}) 求出答案即可。
LOJ6102:「2017 山东二轮集训 Day1」第三题
首先有个性质 (gcd(f_i,f_j)=f_{gcd(i,j)})
根据最值反演不难发现有:$$prod_{Tsubset S,T
e phi}f(gcd(T))^{(-1)^{|T|+1}}$$
爆推:
设 (g_i=sum_{Tsubset S,T
e phi}{(-1)^{|T|+1}}[i|gcd(T)])。
可以发现 (g_i=egin{cases}1,exists k_i,d|k_i\ 0,otherwise end{cases})
预处理 (h_d=sum_{d|i}mu(frac{i}{d})g_i),然后直接计算答案即可。
CodeChef:Counting is life
(n,k) 同奇偶的时候,第一问答案显然就是 (2^{k}-1),第二问直接构造生成函数,就是 ([x^n](frac{e^{x}-e^{-x}}{2})^k),直接二项式定理展开即可。
(n,k) 不同奇偶的时候,第一问答案显然就是 (2^{k}-2),第二问即 ([x^n](frac{e^{x}-e^{-x}}{2})^{k-1}(frac{e^{x}+e^{-x}}{2}))
CodeChef:Counting D-sets
每一种方案数一定可以平移,使得每一维都有 (0),考虑只在每一维都有 (0) 的时候计算答案。
显然可以先计算直径至多为 (d) 的减去至多为 (d-1) 的。
考虑容斥,枚举至多 (i) 为没有达到 (0),答案即 (sum_{i=0}^{n}inom{n}{i}(-1)^i2^{(d+1)^{n-i}d^i})
[LOJ6392:「THUPC2018」密码学第三次小作业/Rsa
](https://loj.ac/problem/6392)
因为 (e_1perp e_2),所以 (e_1x+e_2y=1) 有解。
因为 (nperp c_1,nperp c_2),所以 (c_1,c_2) 有逆元。
解出来 (x,y) 之后快速幂即可。
UOJ424:【集训队作业2018】count
设 (A=) 长度为 (n) 的序列 (X),其中的每个数都是 (1) 到 (m) 内的整数,且所有 (1) 到 (m) 内的整数都在序列 (X) 中出现过的方案数。
(B=) 长度为 (n) 的序列 (X),其中的每个数都是 (1) 到 (m) 内的整数,且最大值为 (m) 的方案数。
一个结论:当 (nge m) 的时候,(A=B)
为了证明这个东西,首先假设 (C=) 长度为 (n) 的序列 (X),其中的每个数都是 (1) 到 (m) 内的整数的方案数,然后只要证明 (A=C) 并且 (C=B) 即可。
首先 (B=C),显然对于 (C) 的一个方案,把所有的数加上 (m-max) 与原来序列同构,就可以得到 (B) 了,所以 (Cle B),而根据定义显然 (Cge B),所以 (C=B)。
然后是 (A=C),首先根据定义也有 (Cge A),然后对于 (A) 的每一种方案,在保证下标前后的大小关系不变的条件下,把相同的数从前往后依次变化(强制后面的小于等于前面的),显然和原来的同构,并且一定可以取遍 (m) 个值,所以 (Age C)。
也得到了 (A=B=C)
(B) 比较好算,设 (f_{i,j}) 表示长度为 (i),最大值为 (j) 的序列的个数。
为了保证同构的不算重复,枚举左右拼接的时候强制在达到最大的情况下计算。
也就是
最后 (f_{n,m}) 就是答案。
把数组两维调换 (f_{i,j}=sum_{k=0}^{j-1}f_{i-1,k}f_{i,j-k-1})
写成多项式 (f_i=f_if_{i-1}x+1),那么 (f_i=frac{1}{1-f_{i-1}x})。
不妨假设 (f_i=frac{a_i}{b_i}),那么
写成矩阵的形式
带入单位根矩阵快速幂,然后 (IDFT) 出 (a,b),最后求逆即可。
另外的方法
按照题目的大小关系建立这个序列的笛卡尔树,那么左儿子的一定小于当前点,右儿子大小一定小于等于当前点。
不难发现,合法的笛卡尔树必须满足根到每个点向左走的次数必须 (<m),这个条件在 (nge m) 的条件下就是充要条件(根据上面的东西不难得到)。
可以用左儿子右兄弟的方法(新建超级点),多叉树森林转二叉树,同时也可以每次抽出右边的链实现二叉树转多叉树森林,这样子,一个多叉树森林可以一一对应一个二叉树。
至此,题目可以转化成:有多少个长度为 (2n) 的合法括号序列,每个前缀(左括号 (+),右括号 (-) )不超过 (m)。
也就是 ((0,0)) 走 (2n) 步到 ((n,n)),每次可以向上走或者向右走 (1),使得不超过 (y=x+m) 和 (y=x) 的路径条数。
算法参见 [JLOI2015]骗我呢。
上面的东西好像有点锅,所以可以去看一看 wxh 的口胡QwQ。