Mo的算法计算阵列的“功率”

时间:2016-04-04 14:36:02

标签: c++ algorithm data-structures

最近,我学习Mo's algorithm查询的平方根分解,以加快某些问题的解决方案。

为了练习实现,我一直在尝试使用这个想法解决D. Powerful array(Codeforces的过去竞赛问题)。问题如下:

您有一个n整数array的数组。

考虑任意子阵列subarray。将Ks定义为此子数组中整数s的出现次数。子阵列的 power 被定义为所有整数Ks*Ks*ss的总和(注意,只有正数的项不是零)。

回答q次问题。在每个查询中,给定两个整数lr,计算subarray

它拥有:

limits1
limits2
limits3

使用Mo的算法,我编写的代码可以在complexity中离线解决此问题。我确信使用这种算法和时间复杂度可以解决这个问题,因为我已经检查了其他人接受的代码,他们也使用了类似的算法。

我的代码gets a time limit exceeded verdict

以下是我写的代码:

#include <ios>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <utility>
#include <map>

int sqt;
long long int ans = 0;
long long int arr[200005] = {};
long long int cnt[1000005] = {};
long long int tans[200005] = {};

struct el
{
    int l, r, in;
};

bool cmp(const el &x, const el &y)
{
    if (x.l/sqt != y.l/sqt)
        return x.l/sqt < y.l/sqt;
    return x.r < y.r;
}

el qr[200005];

int main()
{
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    std::cout.tie(NULL);
    int n, q, a, b;
    std::cin >> n >> q;
    sqt = sqrt((double)(n))+27;
    for (int i = 0; i < n; i++)
        std::cin >> arr[i];
    for (int i = 0; i < q; i++)
    {
        std::cin >> a >> b;
        a--; b--;
        qr[i].l = a;
        qr[i].r = b;
        qr[i].in = i;
    }
    std::sort(qr, qr+q, cmp);

    int li = 0; //left iterator
    int ri = 0; //right iterator
    ans = arr[0];
    cnt[arr[0]]++;

    for (int i = 0; i < q; i++)
    {
        while (li < qr[i].l)
        {
            ans -= cnt[arr[li]]*cnt[arr[li]]*arr[li];
            cnt[arr[li]]--;
            ans += cnt[arr[li]]*cnt[arr[li]]*arr[li];
            li++;
        }
        while (li > qr[i].l)
        {
            li--;
            ans -= cnt[arr[li]]*cnt[arr[li]]*arr[li];
            cnt[arr[li]]++;
            ans += cnt[arr[li]]*cnt[arr[li]]*arr[li];
        }
        while (ri < qr[i].r)
        {
            ri++;
            ans -= cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
            cnt[arr[ri]]++;
            ans += cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
        }
        while (ri > qr[i].r)
        {
            ans -= cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
            cnt[arr[ri]]--;
            ans += cnt[arr[ri]]*cnt[arr[ri]]*arr[ri];
            ri--;
        }
        tans[qr[i].in] = ans;
    }
    for (int i = 0; i < q; i++)
        std::cout << tans[i] << '\n';
}

你能否提出任何非渐近(或甚至可能是渐近)的改进,可以加快程序的速度,足以超过时限?

我已经尝试过以下事情,但无济于事:

  1. 使用向量而不是数组。
  2. 使用两个嵌套对而不是struct。
  3. 仅使用一对,然后使用地图尝试恢复正确的答案顺序。
  4. sqt添加一些不同的常量(例如上面代码中的27)。
  5. 重载&lt; struct el本身内的比较运算符。
  6. 我觉得我错过了一些重要的东西,因为我检查的其他代码似乎已经过了很长的时间(大约半秒钟)。然而,他们似乎使用与我的代码相同的算法。

    任何帮助都将受到高度赞赏!

2 个答案:

答案 0 :(得分:1)

你可以强度减少

    while (li < qr[i].l)
    {
        ans -= cnt[arr[li]]*cnt[arr[li]]*arr[li];
        cnt[arr[li]]--;
        ans += cnt[arr[li]]*cnt[arr[li]]*arr[li];
        li++;
    }

    while (li < qr[i].l)
    {
        ans -= (2*cnt[arr[li]]-1)*arr[li];
        cnt[arr[li]]--;
        li++;
    }

同样适用于其他人。

答案 1 :(得分:1)

您可以修改 MO的排序功能比较器功能cmp

您的版本:

exports.handler = async (event) => {
    try {
        const data = await httprequest();

        //date to string

        var d = Date();
        var n = d.toString();
        var iden = Date.now();
        var identifier = iden.toString();

        //add items to DynamoDB

        console.log("LENGTH IS: " + data.response.docs.length);

        for (var i = 0; i < data.response.docs.length; i++) {

            var params = {
            Item: {
                    date: identifier,
                    time: n,
                    id: data.response.docs[i].id,
                    journal: data.response.docs[i].journal

                },

                TableName: 'employee'
            };

            console.log(data.response.docs[i].id);
            await docClient.put(params).promise();
        }

        console.log('Document inserted.');

        return JSON.stringify(data);
    } catch(err) {
        console.log(err);

        return err;
    }
};

优化:

如果块是偶数,则可以按降序对R进行排序,如果块是奇数,则可以按升序对R进行排序。当从一个块移动到另一个块时,这将大大减少R指针的移动。

我的代码:

  <input list="site" name="f" minlength="2" style="height:5.1em">
  <datalist id="site" style="height:5.1em;overflow:hidden">