ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Farmer John Solves 3SUM

2021-07-24 23:03:46  阅读:224  来源: 互联网

标签:return Solves leq 3SUM int Farmer John getchar


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​ , 可用二维前缀、后缀和计算。

时间复杂度:

  • 预处理 : 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')
            { // \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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有