51nod 1964 陵陵曾玩的数论题

题目描述:

腾腾是一名数论大师,经常在51nod上切高分数论题。凭借着高超的实力,拿到了51nod的#2。

  陵陵是腾腾的好朋友。2017年1月,他还在苦恼一直都不会刷>=320分数论题。一天,他拿到了栋栋寄来的一道数论题。不幸的是,陵陵看错了这道数论题的题意,他感觉这太难了,于是只能拿去问腾腾:给定一个长度为n的序列a,对于一个区间[l,r],如果al,al+1……ar的最小公倍数记作lcm,最大值记作max,这个区间[l,r]的价值定义为 lcmmaxlcmmax (即lcm的max次幂)。现在对于任意区间[l,r](1<=l<=r<=n),陵陵希望知道它们价值的乘积。由于答案可能很大,需要模10^9+7。

  栋栋尝试让别人帮助他解决这个看错的问题,可是10个月过去,从一个赛季到下一个赛季,这个问题都没有解决,陵陵也不再苦恼数论题,而是刷着数学题,腾腾好久不打51nod,也降到了#3。

  幸好,你来了,你一定能解决这个问题。需要注意的是,你的空间不能太大。


 收起

输入

第一行读入一个正整数n表示序列的长度。
接下来一行,n个正整数表示这个序列。
n<=100000,序列每个数均不超过100000。

输出

输出一个整数表示答案,请对10^9+7取模。

输入样例

4
2 3 1 4

输出样例

155362899

题解:

强烈建议在阅读时动手设计一下算法流程。会有助于理解。
解决此题。必须知道下面T(n)T(n)的增张速度。
T(n)=maxk=1n(T(k−1)+T(n−k)+min(k,n−k+1))
T(n)=maxk=1n(T(k−1)+T(n−k)+min(k,n−k+1))
上式子可以看作有一排石子。
合并编号[1,k−1][1,k−1]的石子。代价T(k−1)T(k−1)
合并编号[k,n−1][k,n−1]的式子。代价T(n−k)T(n−k)
把[1,k−1][1,k−1]和[k,n−1][k,n−1]以及第nn个式子合并起来.
代价T(k−1)+T(n−k)+min(k,n−k+1)T(k−1)+T(n−k)+min(k,n−k+1)
显然。这相当于。石子较少的那一堆石子的贡献全部+1+1
显然。一个石子只能对编号是它两倍的石子产生新的贡献。
所以:
T(n)=O(nlog2n)
T(n)=O(nlog2n)
对于区间的所有价值。考虑在笛卡尔树上进行计算。
某一节点以及以这个节点为根的子树组成一段区间。并且根节点是最大值(相同大小。按位置对比)
显然。直观的想法。就是在笛卡尔树上计算所有区间价值。
因为最棘手的部分即使区间的价值计算时maxmax次方。
这样在笛卡尔树上计算maxmax的大小是一样的。所以可以一次性统一处理。
记:m=⌊105−−−√⌋m=⌊105⌋
会发现。如果P>mP>m.那么意味着所有元素都最多只含有一个PP
那么意味着。我们只需要知道。上一次或者下一次这两个位置之间是否可以包含根节点。如果包含。最小范围是多少。便可以得到PP对当前区间的贡献了。
所以我们只需要预处理出来PP上一次出现的位置。便可以搞定这部分计算。
对于这种思路。那么必然需要两个区间之间的合并。
那么我们枚举节点数量较少的那个区间。启发式的合并。
这个复杂度就是:
T(n)=maxk=1n(T(k−1)+T(n−k)+min(k,n−k+1))=O(nlog2n)
T(n)=maxk=1n(T(k−1)+T(n−k)+min(k,n−k+1))=O(nlog2n)
你会发现。我们只是枚举了一侧区间。这就产生了一个问题。
如果枚举的一次没有出现P′P′,但另一侧有P′P′
那么这种方法。P′P′的贡献我们是算不出来的。
但因为我们枚举的一侧没有P′P′,这就是说。我们不管如何选择区间枚举一侧的端点。P′P′的贡献是一样的。
这句话说的有些笼统。考虑区间选择。
如果我们枚举一侧枚举到某一端点时。那么另一侧P′P′所有选择的贡献总和与端点无关。便可以通过快速幂计算。
那么问题是我们需要维护所有PP的贡献。不单单只有P′P′
如果上面你想明的白了。那么贡献是一个什么样的形式就很清楚了。
显然。有两个方向不同的贡献。
我们记。向右延伸的贡献为ARAR
对应的。向左延伸的贡献为ALAL
我们在枚举的同时。剔除ARAR,ALAL中两侧都有的素数的贡献。因为这部分贡献已经计算过了。
我们维护AR,ALAR,AL时,还需要知道整个区间内不同素数的乘积。这是因为计算时候只枚举一侧。所产生问题所必须做的事情。
至此。P>mP>m这部分的贡献已经OKOK了
<script id="MathJax-Element-39" type="math/tex; mode=display"></script>
现在计算P≤mP≤m这部分的贡献。
这部分贡献。因为PP的种数较少。所以可以单独计算。
对于每种PP,我们只需要考虑指数大小。取区间指数最大的那个数就好。
显然我们需要知道指数第一个大于它的数前后位置。
如果大小相同。按照位置对比。必须有一个大小关系。避免重复
依然考虑枚举数量较小的那一测。
这意味着我们需要不断的查询某一侧的总体贡献。
我们预处理出来前后指数大于它的元素位置。通过这个位置查询。
显然这样暴力是不行的。但是我们会发现。查询一次可以把路径压缩了。
而路径压缩的耗费是可以 单独考虑的。
其与总路径数量是线性的。
显然:一个节点 最多链接两条边
那么。总路径数量是O(n)O(n)
所以总的时间复杂度就是
O(nn−−√∗log2nlogen+nlog22n),题中。最大值和最大元素数量可以同时为n
O(nn∗log2nlogen+nlog22n),题中。最大值和最大元素数量可以同时为n
由于所给空间比较小。强烈建议BFSDFS过程可能会保存过多无用变量。递归深度过深。所以笛卡尔树建树时一定要存储区间范围。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <cmath>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
const int mod_1 = mod - 1;
const int MAXN = 100003;
const int Sqr = (int)sqrt(MAXN) + 1;
struct Io
{
    char A[MAXN * 4],*L,*R;
    int count;
    Io()
    {
        L &
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值