NO.1 HDU - 3448
分类: 枚举,meet-in-the-middle
简要题解:
- 暴力枚举每个物品是否被选的时间复杂度是O(2n)O(2n)
- 枚举前一半物品,处理出n2n2个set,其中集合SiSi里面存着不多于ii 个物品的所有可能重量和
- 再枚举后一半物品,再对应集合中二分查找即可
- 时间复杂度降为
反思
- 这种操作被称为meet-in-the-middle
NO.2 HDU - 3445
分类: 组合数学
简要题解:
- 考虑Δf(0)=∏(ai+1)−∏ai=∑S∏ai∈SaiΔf(0)=∏(ai+1)−∏ai=∑S∏ai∈Sai 其中SS是的一个真子集(其实一次差分就是选一些元素不要,然后求和)
- 在k次差分之后,对于{a1,a2,...an}{a1,a2,...an}的任意一个子集,设SS的元素个数为,这一项对答案的贡献是k!∗{kn−|S|}∗∏ai∈Sai,{nk}k!∗{n−|S|k}∗∏ai∈Sai,{kn}表示第二类斯特林数(把n个不标号元素组成k个非空集合的方案数).
- 上面那个式子的意思就是把n−|S|n−|S|个带标号的元素分kk次甩出去…
- 最后恰好除了一个,只需要预处理f(t)=∑[|S|=t]∗∏ai∈Saif(t)=∑[|S|=t]∗∏ai∈Sai
反思
- 难得一批
- 找规律可以发现所求的式子可以表示为∑0≤i≤kCik∗(−1)i−k∗f(i)∑0≤i≤kCki∗(−1)i−k∗f(i),然而并没有什么用,因为那个除以k!k!没办法处理
- 上面那个式子虽然没什么用,但也可以证明其正确性:定义算子δ[f(n)]=f(n+1),I[f(n)]=f(n)δ[f(n)]=f(n+1),I[f(n)]=f(n) 不难验证δ,Iδ,I满足交换律和结合律,显然Δ[f(k)]=(δ−I)[f(k)]Δ[f(k)]=(δ−I)[f(k)] 从而Δkf(n)=(δ−I)k[f(n)]Δkf(n)=(δ−I)k[f(n)]用二项式定理展开就得到了求和展开式
NO.3 HackerRank : nominating-group-leaders
分类: 莫队,分块
简要题解:
- 询问显然可以用莫队算法离线
- 容易想到用set来维护每种票数对应的人,然而修改的次数多达nn‾√nn次,无法通过.
- 注意到查询次数是105105 级别的,用分块算法可以做到O(1)O(1)修改,O(n‾√)O(n)查询,问题得以解决. - 具体实现方面记录一个block_cnt(i,x)block_cnt(i,x)表示第ii块里票数为的人的个数即可
反思
- 对于动态修改查询问题,不要局限于一种方法,平衡修改和查询的时间复杂度来满足题目需要才是重要的
NO.4 HackerRank : colliding-circles
分类: 数学,期望
简要题解:
- 考虑合成的一个大圆对答案的贡献:π∗(∑ri)2π∗(∑ri)2展开之后可以得到π∗∑i,jrirjπ∗∑i,jrirj
- 那么问题转化为求∑i,jp(i,j)∗rirj∑i,jp(i,j)∗rirj 其中p(i,j)p(i,j)表示i,ji,j两圆在同一组的概率
- 当i=ji=j时,显然有p(i,i)=1p(i,i)=1,否则等于另一个值,记为f(n,k)f(n,k)
- 那么f(n,k)f(n,k)表示的是开始有n个圆,k次合并之后任意两圆在同一组的概率.
- 考虑第一次合并的情况可以得到f(n,k)=p+(1−p)∗f(n−1,k−1),p=1C2nf(n,k)=p+(1−p)∗f(n−1,k−1),p=1Cn2
- 最终的答案就是∑r2i+[(∑ri)2−∑r2i]∗f(n,k)∑ri2+[(∑ri)2−∑ri2]∗f(n,k)
反思
- 一道很好的求数学期望的题目
- 直接寻找答案状态很难啊,突破点在于考虑每两个圆对答案的贡献.