我是靠谱客的博主 平淡鸡,最近开发中收集的这篇文章主要介绍Farmer John Solves 3SUM F a r m e r   J ,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

F a r m e r   J o h n   S o l v e s   3 S U M Farmer John Solves 3SUM Farmer John Solves 3SUM

题目描述

F a r m e r   J o h n Farmer John Farmer John 相信他在算法设计上实现了一个重大突破:他声称他发现了一个 3 S U M 3SUM 3SUM 问题的近似线性时间算法,这是一个有名的算法问题,尚未发现比运行速度比平方时间明显更优的解法。 3 S U M 3SUM 3SUM 问题的一个形式是:给定一个整数数组 s 1 , … , s m s_1,ldots,s_m s1,,sm,计算不同索引组成的无序三元对 i , j , k i,j,k i,j,k 的数量,使得 s i + s j + s k = 0 s_i + s_j + s_k = 0 si+sj+sk=0

为了测试 F a r m e r   J o h n Farmer John Farmer John 的断言, B e s s i e Bessie Bessie 提供了一个 N N N 个整数组成的数组 A A A 1 ≤ N ≤ 5000 1 leq N leq 5000 1N5000)。 B e s s i e Bessie Bessie 还会进行 Q Q Q 次询问( 1 ≤ Q ≤ 1 0 5 1 leq Q leq 10^5 1Q105),每个询问由两个索引 1 ≤ a i ≤ b i ≤ N 1 leq a_i leq b_i leq N 1aibiN 组成。对于每个询问, F a r m e r   J o h n Farmer John Farmer John 必须在子数组 A [ a i … b i ] A[a_i ldots b_i] A[aibi] 上求解 3 S U M 3SUM 3SUM 问题。

不幸的是, F a r m e r   J o h n Farmer John Farmer John 刚刚发现了他的算法中的一个错误。他很自信他能修复这个算法,但同时,他请你帮他先通过 B e s s i e Bessie Bessie 的测试!

输入格式

输入的第一行包含两个空格分隔的整数 N N N Q Q Q

第二行包含空格分隔的数组 A A A 的元素 A 1 , … , A N A_1,ldots ,A_N A1,,AN

以下 Q Q Q 行每行包含两个空格分隔的整数 a i a_i ai b i b_i bi ,表示一个询问。

保证对于每个数组元素 A i A_i Ai − 1 0 6 ≤ A i ≤ 1 0 6 -10^6 leq A_i leq 10^6 106Ai106

输出格式

输出包含 Q Q Q 行,第 i i i 行包含一个整数,为第 i i i 个询问的结果。注意你需要使用 64 64 64 位整数型来避免溢出。

输入输出样例

输入 #1

7 3
2 0 -1 1 -2 3 3
1 5
2 4
1 7

输出 #1

2
1
4

说明/提示

样例解释

对于第一个询问,所有的三元对为 ( A 1 , A 2 , A 5 ) (A_1,A_2,A_5) (A1,A2,A5) ( A 2 , A 3 , A 4 ) (A_2,A_3,A_4) (A2,A3,A4)

题目大意

有一个长度为 N N N 的序列 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an

Q Q Q 次询问,每次给定 l l l r r r ,问有多少三元组 ( i , j , k ) (i,j,k) (i,j,k) 满足 l ≤ i < j < k ≤ r lleq i < j < k leq r li<j<kr a i + a j + a k = 0 a_i + a_j + a_k = 0 ai+aj+ak=0

数据范围 : 1 ≤ N ≤ 5000 , − 1 0 6 ≤ a i ≤ 1 0 6 , 1 ≤ Q ≤ 1 0 5 1 leq N leq 5000 , -10^6 leq a_i leq 10^6 , 1 leq Q leq 10^5 1N5000,106ai106,1Q105

解题思路

首先对于所有可能的 i , k i,k i,k ( 1 ≤ i < k ≤ N 1 leq i < k leq N 1i<kN) , 计算有多少 j j j 满足 i < j < k i < j < k i<j<k a j = − a i − a k a_j=-a_i-a_k aj=aiak,记作 f i , k f_{i,k} fi,k

查找的过程可以用桶来实现,但要记得每次找完一个区间 [ i , k ] [i,k] [i,k] 内的 j j j 时,记得把桶清空。

需要注意的是 a i a_i ai 可能为负数,所以对每一个要在桶操作的数,都得加上一个足够大的数,保证数组的下标不能是负数。

对于一组询问 l , r l,r l,r ,答案即为 ∑ i = l r ∑ k = i r f i , k sumlimits_{i=l}^r sumlimits_{k=i}^r f_{i,k} i=lrk=irfi,k , 可用二维前缀、后缀和计算。

时间复杂度:

  • 预处理 : O ( N 2 ) O(N^2) O(N2)
  • 查询 : O ( 1 ) O(1) O(1)

A C   c o d e AC code AC code

阅读时请省略快读 —— QAQ

#include <bits/stdc++.h>
#define int long long
#define _ 1000000
using namespace std;

/* --------------- fast io --------------- */ // begin
namespace Fread
{
    const int SIZE = 1 << 21;
    char buf[SIZE], *S, *T;
    inline char getchar()
    {
        if (S == T)
        {
            T = (S = buf) + fread(buf, 1, SIZE, stdin);
            if (S == T)
                return 'n';
        }
        return *S++;
    }
} // namespace Fread
namespace Fwrite
{
    const int SIZE = 1 << 21;
    char buf[SIZE], *S = buf, *T = buf + SIZE;
    inline void flush()
    {
        fwrite(buf, 1, S - buf, stdout);
        S = buf;
    }
    inline void putchar(char c)
    {
        *S++ = c;
        if (S == T)
            flush();
    }
    struct NTR
    {
        ~NTR() { flush(); }
    } ztr;
} // namespace Fwrite
#ifdef ONLINE_JUDGE
#define getchar Fread ::getchar
#define putchar Fwrite ::putchar
#endif
namespace Fastio
{

    struct Reader
    {
        template <typename T>
        Reader &operator>>(T &x)
        {
            char c = getchar();
            T f = 1;
            while (c < '0' || c > '9')
            {
                if (c == '-')
                    f = -1;
                c = getchar();
            }
            x = 0;
            while (c >= '0' && c <= '9')
            {
                x = x * 10 + (c - '0');
                c = getchar();
            }
            x *= f;
            return *this;
        }

        Reader &operator>>(char &c)
        {
            c = getchar();
            while (c == ' ' || c == 'n')
            {
                c = getchar();
            }
            return *this;
        }
        Reader &operator>>(char *str)
        {
            int len = 0;
            char c = getchar();
            while (c == ' ' || c == 'n')
            {
                c = getchar();
            }
            while (c != ' ' && c != 'n' && c != 'r')
            { // rn in windows
                str[len++] = c;
                c = getchar();
            }
            str[len] = '';
            return *this;
        }
        Reader() {}
    } cin;
    const char endl = 'n';
    struct Writer
    {

        template <typename T>
        Writer &operator<<(T x)
        {
            if (x == 0)
            {
                putchar('0');
                return *this;
            }
            if (x < 0)
            {
                putchar('-');
                x = -x;
            }
            static int sta[45];
            int top = 0;
            while (x)
            {
                sta[++top] = x % 10;
                x /= 10;
            }
            while (top)
            {
                putchar(sta[top] + '0');
                --top;
            }
            return *this;
        }
        Writer &operator<<(char c)
        {
            putchar(c);
            return *this;
        }
        Writer &operator<<(char *str)
        {
            int cur = 0;
            while (str[cur])
                putchar(str[cur++]);
            return *this;
        }
        Writer &operator<<(const char *str)
        {
            int cur = 0;
            while (str[cur])
                putchar(str[cur++]);
            return *this;
        }
        Writer() {}
    } cout;
} // namespace Fastio
#define cin Fastio ::cin
#define cout Fastio ::cout
#define endl Fastio ::endl

/* --------------- fast io --------------- */ // end

int n, q;
int a, b;

int c[5005];
int f[5005][5005];
int d[4000005];

int col(int x)
{
    return x + (_ << 1);
}

signed main()
{
    cin >> n >> q;

    for (register int i = 1; i <= n; ++i)
    {
        cin >> c[i];
    }

    for (register int i = 1; i <= n; ++i)
    {
        for (register int j = i + 1; j <= n; ++j)
        {
            f[i][j] = d[col(-c[i] - c[j])];
            d[col(c[j])]++;
        }
        for (register int j = i + 1; j <= n; ++j)
        {
            d[col(c[j])] = 0;
        }
    }

    for (register int len = 3; len <= n; ++len)
    {
        for (register int i = 1; i + len - 1 <= n; ++i)
        {
            int j = i + len - 1;
            f[i][j] += f[i + 1][j] + f[i][j - 1] - f[i + 1][j - 1];
        }
    }

    while (q--)
    {
        cin >> a >> b;
        cout << f[a][b] << endl;
    }

    return 0;
}

最后

以上就是平淡鸡为你收集整理的Farmer John Solves 3SUM F a r m e r   J 的全部内容,希望文章能够帮你解决Farmer John Solves 3SUM F a r m e r   J 所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部