其他分享
首页 > 其他分享> > Farmer John Solves 3SUM

Farmer John Solves 3SUM

作者:互联网

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 1≤N≤5000)。 B e s s i e Bessie Bessie 还会进行 Q Q Q 次询问( 1 ≤ Q ≤ 1 0 5 1 \leq Q \leq 10^5 1≤Q≤105),每个询问由两个索引 1 ≤ a i ≤ b i ≤ N 1 \leq a_i \leq b_i \leq N 1≤ai​≤bi​≤N 组成。对于每个询问, 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[ai​…bi​] 上求解 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 −106≤Ai​≤106 。

输出格式

输出包含 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 l\leq i < j < k \leq r l≤i<j<k≤r 且 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 1≤N≤5000,−106≤ai​≤106,1≤Q≤105 。

解题思路

首先对于所有可能的 i , k i,k i,k ( 1 ≤ i < k ≤ N 1 \leq i < k \leq N 1≤i<k≤N) , 计算有多少 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​=−ai​−ak​,记作 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 \sum\limits_{i=l}^r \sum\limits_{k=i}^r f_{i,k} i=l∑r​k=i∑r​fi,k​ , 可用二维前缀、后缀和计算。

时间复杂度:

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')
            { // \r\n in windows
                str[len++] = c;
                c = getchar();
            }
            str[len] = '\0';
            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;
}

标签:return,Solves,leq,3SUM,int,Farmer,John,getchar
来源: https://blog.csdn.net/qq_46258139/article/details/119065390