51nod 1964 1964 陵陵曾玩的数论题

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1964

强烈建议在阅读时动手设计一下算法流程。会有助于理解。

解决此题。必须知道下面 T(n) 的增张速度。

T(n)=maxk=1n(T(k1)+T(nk)+min(k,nk+1))

上式子可以看作有一排石子。

合并编号 [1,k1] 的石子。代价 T(k1)

合并编号 [k,n1] 的式子。代价 T(nk)

[1,k1] [k,n1] 以及第 n 个式子合并起来.

代价T(k1)+T(nk)+min(k,nk+1)

显然。这相当于。石子较少的那一堆石子的贡献全部 +1

显然。一个石子只能对编号是它两倍的石子产生新的贡献。

所以:
T(n)=O(nlog2n)

对于区间的所有价值。考虑在笛卡尔树上进行计算。

某一节点以及以这个节点为根的子树组成一段区间。并且根节点是最大值(相同大小。按位置对比)

显然。直观的想法。就是在笛卡尔树上计算所有区间价值。

因为最棘手的部分即使区间的价值计算时 max 次方。

这样在笛卡尔树上计算 max 的大小是一样的。所以可以一次性统一处理。

记: m=105

会发现。如果 P>m .那么意味着所有元素都最多只含有一个 P

那么意味着。我们只需要知道。上一次或者下一次这两个位置之间是否可以包含根节点。如果包含。最小范围是多少。便可以得到P对当前区间的贡献了。

所以我们只需要预处理出来 P 上一次出现的位置。便可以搞定这部分计算。

对于这种思路。那么必然需要两个区间之间的合并。

那么我们枚举节点数量较少的那个区间。启发式的合并。

这个复杂度就是:

T(n)=maxk=1n(T(k1)+T(nk)+min(k,nk+1))=O(nlog2n)

你会发现。我们只是枚举了一侧区间。这就产生了一个问题。

如果枚举的一次没有出现 P ,但另一侧有 P

那么这种方法。 P 的贡献我们是算不出来的。

但因为我们枚举的一侧没有 P ,这就是说。我们不管如何选择区间枚举一侧的端点。 P 的贡献是一样的。

这句话说的有些笼统。考虑区间选择。

如果我们枚举一侧枚举到某一端点时。那么另一侧 P 所有选择的贡献总和与端点无关。便可以通过快速幂计算。

那么问题是我们需要维护所有 P 的贡献。不单单只有P

如果上面你想明的白了。那么贡献是一个什么样的形式就很清楚了。

显然。有两个方向不同的贡献。

我们记。向右延伸的贡献为 AR

对应的。向左延伸的贡献为 AL

我们在枚举的同时。剔除 AR AL 中两侧都有的素数的贡献。因为这部分贡献已经计算过了。

我们维护 AR,AL 时,还需要知道整个区间内不同素数的乘积。这是因为计算时候只枚举一侧。所产生问题所必须做的事情。

至此。 P>m 这部分的贡献已经 OK

<script id="MathJax-Element-39" type="math/tex; mode=display"></script>

现在计算 Pm 这部分的贡献。

这部分贡献。因为 P 的种数较少。所以可以单独计算。

对于每种P,我们只需要考虑指数大小。取区间指数最大的那个数就好。

显然我们需要知道指数第一个大于它的数前后位置。

如果大小相同。按照位置对比。必须有一个大小关系。避免重复

依然考虑枚举数量较小的那一测。

这意味着我们需要不断的查询某一侧的总体贡献。

我们预处理出来前后指数大于它的元素位置。通过这个位置查询。

显然这样暴力是不行的。但是我们会发现。查询一次可以把路径压缩了。

而路径压缩的耗费是可以 单独考虑的。

其与总路径数量是线性的。

显然:一个节点 最多链接两条边

那么。总路径数量是 O(n)

所以总的时间复杂度就是
O(nnlog2nlogen+nlog22n),n

由于所给空间比较小。强烈建议 BFS DFS 过程可能会保存过多无用变量。递归深度过深。所以笛卡尔树建树时一定要存储区间范围。

#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 = R = A;
        count = MAXN * 4;
    }
    void Io_fread()
    {
        L = A;
        R = A + fread(A, sizeof(char), count, stdin);
    }
    int read()
    {
        int  tmp = 0;
        if (L == R)
        {
            Io_fread();
            if (L == R)return 0;
        }
        while (*L<'0'||*L>'9')
        {
            L++;
            if (L == R)
            {
                Io_fread();
                if (L == R)return 0;
            }
        }
        while (*L >= '0'&&*L <= '9')
        {
            tmp = tmp * 10 + (*L - '0');
            L++;
            if (L == R)
            {
                Io_fread();
                if (L == R)return tmp;
            }
        }
        return tmp;
    }
}I;
int used[MAXN];
int buf[MAXN];
int G[MAXN];
int tmp[MAXN];
int tmp2[MAXN];
int nxt[MAXN];
int fst[MAXN];
int bnxt[MAXN];
int bfst[MAXN];
int queue[MAXN];
int stk[MAXN];
int *wnxt = tmp, *wfst = tmp2, *AL = tmp, *AR = tmp2, *C = used;
int ans = 1;

struct node
{
    int c[2];
    int L, R;
    node()
    {
        L = R = c[0] = c[1] = 0;
    }
};

struct Decare
{
    node A[MAXN];
    int root;
    int deep;
    Decare()
    {
        root = 0;
        deep = 1;
    }
    void _insert(int key, int inof)
    {
        if (inof == 0)
        {
            root = deep++;
            tmp[root] = key;
            return;
        }
        while (inof)
        {
            if (tmp[inof] >= key)
            {
                tmp[deep] = key;
                G[deep] = inof;
                A[deep].c[0] = A[inof].c[1];
                A[inof].c[1] = deep;
                G[A[deep].c[0]] = deep;
                deep++;
                return;
            }
            inof = G[inof];
        }
        tmp[deep] = key;
        A[deep].c[0] = root;
        G[root] = deep;
        root = deep++;
    }
    void insert(int key)
    {
        _insert(key, deep - 1);
    }
    void BFS(int root)
    {
        memset(tmp, 0, sizeof tmp);
        int l = 0, r = 1;
        stk[0] = root;
        while (l < r)
        {
            int v = stk[l++];
            if (A[v].c[0])    stk[r++] = A[v].c[0];
            if (A[v].c[1])    stk[r++] = A[v].c[1];
        }
        int n = r;
        while (r--)
        {
            int v = stk[r];
            tmp[v] ++;
            tmp[G[v]] += tmp[v];
        }
        tmp[0] = 0;
        l = 0;    r = 1;
        A[root].L = 1;
        A[root].R = n;
        A[0].L = 1;
        A[0].R = 0;
        while (l<r)
        {
            int v = stk[l++];
            A[A[v].c[0]].L = A[v].L;
            A[A[v].c[0]].R = A[A[v].c[0]].L + tmp[A[v].c[0]] - 1;
            A[A[v].c[1]].L = A[A[v].c[0]].R + 2;
            A[A[v].c[1]].R = A[A[v].c[1]].L + tmp[A[v].c[1]] - 1;
            if (A[v].c[0])   stk[r++] = A[v].c[0];
            if (A[v].c[1])   stk[r++] = A[v].c[1];
        }
        memset(tmp, 0, sizeof tmp);
        memset(G, 0, sizeof G);
        A[0].L = 1;
        A[0].R = 0;
    }
}D;

int Pow(int a, int b)
{
    int tmp = 1;
    while (b)
    {
        if (b & 1)
            tmp = (LL)tmp*a%mod;
        a = (LL)a*a%mod;
        b >>= 1;
    }
    return tmp;
}

int A[MAXN];

int find_nxt(int k, int B)
{
    int top = -1, d = k;
    while (bnxt[d] <= B)
    {
        stk[++top] = d;
        d = bnxt[d];
    }
    while (top>-1)
    {
        int x = stk[top--];
        if (bnxt[x] == nxt[x])wnxt[x] = A[x] * (bnxt[x] - x);
        wnxt[x] += wnxt[bnxt[x]];
        bnxt[x] = d;
    }
    return wnxt[k] + (B - d + 1)*A[d];
}

int find_fst(int k, int B)
{
    int top = -1, d = k;
    while (bfst[d] >= B)
    {
        stk[++top] = d;
        d = bfst[d];
    }
    while (top>-1)
    {
        int x = stk[top--];
        if (bfst[x] == fst[x]) wfst[x] = A[x] * (x - bfst[x]);
        wfst[x] += wfst[bfst[x]];
        bfst[x] = d;
    }
    return wfst[k] + (d - B + 1)*A[d];
}

void BFS_1(int root, int P)
{
    int l = 0, r = 1;
    queue[0] = root;
    while (l < r)
    {
        int v = queue[l++];
        if (D.A[v].c[0])queue[r++] = D.A[v].c[0];
        if (D.A[v].c[1])queue[r++] = D.A[v].c[1];
    }
    while (r--)
    {
        int v = queue[r];
        int *c = D.A[v].c;
        int L = D.A[v].L;
        int R = D.A[v].R;
        if (L == R)
        {
            G[P] = (G[P] + (LL)A[L] * buf[L] % (mod_1)) % mod_1;
            continue;
        }

        int mid = (c[0]) ? D.A[c[0]].R + 1 : D.A[c[1]].L - 1;

        if ((D.A[c[0]].R - D.A[c[0]].L + 1)<(D.A[c[1]].R - D.A[c[1]].L + 1))
        {
            for (int i = mid; i >= L; i = fst[i])
            {
                if (nxt[i] <= R)
                {
                    int bk = fst[i] < L ? L : fst[i] + 1;
                    G[P] += ((LL)(i - bk + 1)*(nxt[i] - mid) % (mod - 1))*((LL)A[i] * buf[mid] % (mod - 1)) % (mod - 1);
                    if (G[P] >= mod - 1)G[P] -= mod - 1;
                    G[P] += (LL)(i - bk + 1)*(buf[mid]) % (mod - 1)*find_nxt(nxt[i], R) % (mod - 1);
                    if (G[P] >= mod - 1)G[P] -= mod - 1;
                }
                else
                {
                    int bk = fst[i]<L ? L : fst[i] + 1;
                    G[P] += ((LL)(i - bk + 1)*(R - mid + 1) % (mod - 1))*((LL)A[i] * buf[mid] % (mod - 1)) % (mod - 1);
                    if (G[P] >= mod - 1)G[P] -= mod - 1;
                }
            }
        }
        else
        {
            for (int i = mid; i <= R; i = nxt[i])
            {
                if (fst[i] >= L)
                {
                    int bk = nxt[i]>R ? R : nxt[i] - 1;
                    G[P] += ((LL)(bk - i + 1)*(mid - fst[i]) % (mod - 1))*((LL)A[i] * buf[mid] % (mod - 1)) % (mod - 1);
                    if (G[P] >= mod - 1)G[P] -= mod - 1;;
                    G[P] += (LL)(bk - i + 1)*buf[mid] % (mod - 1)*find_fst(fst[i], L) % (mod - 1);
                    if (G[P] >= mod - 1)G[P] -= mod - 1;
                }
                else
                {
                    int bk = nxt[i]>R ? R : nxt[i] - 1;
                    G[P] += ((LL)(bk - i + 1)*(mid - L + 1) % (mod - 1))*((LL)A[i] * buf[mid] % (mod - 1)) % (mod - 1);
                    if (G[P] >= mod - 1)G[P] -= mod - 1;
                }
            }
        }
    }
}

void BFS_2(int root)
{
    int l = 0, r = 1;
    queue[0] = root;
    while (l < r)
    {
        int v = queue[l++];
        if (D.A[v].c[0])queue[r++] = D.A[v].c[0];
        if (D.A[v].c[1])queue[r++] = D.A[v].c[1];
    }

    while (r--)
    {
        root = queue[r];
        int *c = D.A[root].c;
        int L = D.A[root].L;
        int R = D.A[root].R;
        if (L == R)
        {
            G[A[buf[L]]] = (G[A[buf[L]]] + buf[L]) % mod_1;
            AL[root] = AR[root] = C[root] = A[buf[L]];
            continue;
        }
        int mid = (c[0]) ? D.A[c[0]].R + 1 : D.A[c[1]].L - 1;
        int tot = (LL)(mid - L + 1)*(R - mid + 1) % mod_1;
        if ((D.A[c[0]].R - D.A[c[0]].L) < (D.A[c[1]].R - D.A[c[1]].L))
        {
            AR[root] = (LL)AR[c[0]] * AR[c[1]] % mod;
            AL[root] = (LL)AL[c[0]] * AL[c[1]] % mod;
            C[root] = (LL)C[c[0]] * C[c[1]] % mod;
            for (int i = mid; i >= L; i--)
            {
                int &bk = nxt[i];
                if (bk <= mid)continue;
                int a = A[buf[i]];
                if (bk > R)
                {
                    G[a] += (LL)buf[mid] * (i - L + 1) % mod_1*(R - mid + 1) % mod_1;
                    if (G[a] >= mod_1)G[a] -= mod_1;
                    AR[root] = (LL)AR[root] * Pow(A[buf[i]], R - mid + 1) % mod;
                    int b = (i == mid) ? (fst[i]<L ? L : fst[i] + 1) : mid + 1;
                    AL[root] = (LL)AL[root] * Pow(A[buf[i]], mid - b + 1) % mod;
                    if ((i == mid && fst[i] >= L) || i != mid)
                        C[c[0]] = (LL)C[c[0]] * Pow(A[buf[i]], mod - 2) % mod;
                }
                else
                {
                    //bk<=R
                    int b = tot - (LL)(mid - i)*(bk - mid) % mod_1;
                    if (b < 0)b += mod_1;
                    G[a] += (LL)buf[mid] * b % mod_1;
                    if (G[a] >= mod_1)G[a] -= mod_1;
                    AR[c[1]] = (LL)AR[c[1]] * Pow(A[buf[i]], (LL)(mod - 2)*(R - bk + 1) % mod_1) % mod;
                    C[c[1]] = (LL)C[c[1]] * Pow(A[buf[i]], mod - 2) % mod;
                    if (i != mid)
                    {
                        C[c[0]] = (LL)C[c[0]] * Pow(A[buf[i]], mod - 2) % mod;
                        C[root] = (LL)C[root] * Pow(A[buf[i]], mod - 2) % mod;
                        AL[root] = (LL)AL[root] * Pow(A[buf[i]], mid - i) % mod;
                    }
                    else
                    {
                        C[c[0]] = (LL)C[c[0]] * (fst[i]<L ? 1 : Pow(A[buf[i]], mod - 2)) % mod;
                        C[root] = (LL)C[root] * (fst[i]<L ? 1 : Pow(A[buf[i]], mod - 2)) % mod;
                        AL[root] = (LL)AL[root] * Pow(A[buf[i]], mid + 1 - ((fst[i]<L) ? L : fst[i] + 1)) % mod;
                    }
                    AR[root] = (LL)AR[root] * Pow(A[buf[i]], bk - mid) % mod;//
                }
            }
            ans = (LL)ans*Pow(AR[c[1]], (LL)(mid - L + 1)*buf[mid] % (mod - 1)) % mod;
            AL[root] = (LL)AL[root] * Pow(C[c[1]], mid - L + 1) % mod;
            if (nxt[mid]>R&&fst[mid]<L) C[root] = (LL)C[root] * A[buf[mid]] % mod;
        }
        else
        {
            AR[root] = (LL)AR[c[0]] * AR[c[1]] % mod;
            AL[root] = (LL)AL[c[0]] * AL[c[1]] % mod;
            C[root] = (LL)C[c[0]] * C[c[1]] % mod;
            for (int j = mid; j <= R; j++)
            {
                int &bk = fst[j];
                int a = A[buf[j]];
                if (bk >= mid)continue;
                if (bk < L)
                {
                    G[a] += (LL)buf[mid] * (mid - L + 1) % (mod - 1)*(R - j + 1) % (mod - 1);
                    if (G[a] >= mod - 1)G[a] -= mod - 1;
                    AL[root] = (LL)AL[root] * Pow(A[buf[j]], mid - L + 1) % mod;
                    int b = (j == mid) ? (nxt[j] <= R ? nxt[j] - 1 : R) : mid - 1;
                    AR[root] = (LL)AR[root] * Pow(A[buf[j]], b - mid + 1) % mod;
                    if ((j == mid&&nxt[j] <= R) || j != mid)
                        C[c[1]] = (LL)C[c[1]] * Pow(A[buf[j]], mod - 2) % mod;
                }
                else
                {
                    int b = tot - (LL)(mid - bk)*(j - mid) % mod_1;
                    if (b < 0)b += mod_1;
                    G[a] += (LL)buf[mid] * b % mod_1;
                    if (G[a] >= mod - 1)G[a] -= mod_1;
                    AL[c[0]] = (LL)AL[c[0]] * Pow(A[buf[j]], (LL)(bk - L + 1)*(mod - 2) % mod_1) % mod;
                    C[c[0]] = (LL)C[c[0]] * Pow(A[buf[j]], mod - 2) % mod;
                    if (j != mid)
                    {
                        C[c[1]] = (LL)C[c[1]] * Pow(A[buf[j]], mod - 2) % mod;
                        C[root] = (LL)C[root] * Pow(A[buf[j]], mod - 2) % mod;
                        AR[root] = (LL)AR[root] * Pow(A[buf[j]], j - mid) % mod;
                    }
                    else
                    {
                        C[c[1]] = (LL)C[c[1]] * ((nxt[j] <= R) ? Pow(A[buf[j]], mod - 2) : 1) % mod;
                        C[root] = (LL)C[root] * ((nxt[j] <= R) ? Pow(A[buf[j]], mod - 2) : 1) % mod;
                        AR[root] = (LL)AR[root] * Pow(A[buf[mid]], ((nxt[j]>R) ? R : nxt[j] - 1) - mid + 1) % mod;
                    }
                    AL[root] = (LL)AL[root] * Pow(A[buf[j]], mid - bk) % mod;
                }
            }
            ans = (LL)ans*Pow(AL[c[0]], (LL)(R - mid + 1)*buf[mid] % mod_1) % mod;
            AR[root] = (LL)AR[root] * Pow(C[c[0]], R - mid + 1) % mod;
            if (nxt[mid]>R&&fst[mid]<L) C[root] = (LL)C[root] * A[buf[mid]] % mod;
        }
    }

}

void init(int n)
{
    A[0] = A[n + 1] = 0x3f3f3f3f;
    for (int i = 2; i < Sqr; i++)
    {
        if (used[i])continue;
        for (int j = i; j < MAXN; j += i)    used[j] = 1;

        for (int j = 1; j <= n; j++)
        {
            A[j] = 0;
            int t = buf[j];
            while (t%i == 0)
            {
                A[j]++;
                t /= i;
            }
        }

        memset(tmp, 0, sizeof tmp);
        memset(tmp2, 0, sizeof tmp2);
        stk[0] = 0;

        for (int j = 1, top = 0; j <= n; j++)
        {
            while (A[stk[top]] < A[j])top--;
            bfst[j] = fst[j] = stk[top];
            stk[++top] = j;
        }
        stk[0] = n + 1;

        for (int j = n, top = 0; j; j--)
        {
            while (A[stk[top]] <= A[j])top--;
            bnxt[j] = nxt[j] = stk[top];
            stk[++top] = j;
        }
        BFS_1(D.root, i);
    }
    for (int i = 0; i < MAXN; i++)A[i] = 1;
    for (int i = Sqr; i < MAXN; i++)
    {
        if (used[i])continue;
        for (int j = i; j < MAXN; j += i)
        {
            used[j] = 1;
            A[j] = i;
        }
    }
    memset(tmp, 0, sizeof tmp);
    for (int i = 1; i <= n; i++)
    {
        fst[i] = tmp[A[buf[i]]];
        tmp[A[buf[i]]] = i;
    }
    for (int i = 0; i < MAXN; i++)tmp[i] = n + 1;
    for (int j = n; j; j--)
    {
        nxt[j] = tmp[A[buf[j]]];
        tmp[A[buf[j]]] = j;
    }
    memset(tmp, 0, sizeof tmp);
    memset(tmp2, 0, sizeof tmp2);
    memset(used, 0, sizeof used);
    AL[0] = AR[0] = C[0] = 1;
    BFS_2(D.root);
}

int main()
{
    int n;
    n = I.read();
    for (int i = 1; i <= n; i++)
    {
        buf[i] = I.read();
        D.insert(buf[i]);
    }
    D.BFS(D.root);
    init(n);
    for (int i = 2; i < MAXN; i++) ans = (LL)ans*Pow(i, G[i]) % mod;
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值