LG-P6006 [USACO20JAN]Farmer John Solves 3SUM G 题解

区间内三元组个数(满足 a i + a j + a k = 0 ai + aj + ak = 0 ai+aj+ak=0

(GZEZ 新初一第一次测试 第四题)

在指定范围 [ l , r ] [l, r] [l,r] 内,求满足 a i + a j + a k = 0 ai + aj + ak = 0 ai+aj+ak=0 的三元组的个数。


思路:

先预处理,时间复杂度是 O ( n 2 ) O(n^2) O(n2) ; 再查询,时间复杂度是 O ( 1 ) O(1) O(1)

预处理:

  1. 在确定了两端的数之后,中间的数 = − a [ i ] − a [ j ] = -a[i]-a[j] =a[i]a[j],同时用桶去统计各个数的数量,即 d p [ i ] [ j ] = c n t [ m − a [ i ] − a [ j ] ] dp[i][j] = cnt[m - a[i] - a[j]] dp[i][j]=cnt[ma[i]a[j]] d p dp dp 用来记录符合题目条件于 i i i j j j 的三元组的个数; c n t cnt cnt 用作桶,统计各个数出现的次数)。

  2. 记得在第二层循坏外把 c n t cnt cnt 使用过的部分清空。

  3. 之前的 d p [ i ] [ j ] dp[i][j] dp[i][j] 统计的是以 i i i 为首, j j j为末所包含的三元组,若想得到于 [ i , j ] [i,j] [i,j] 内所有的三元组,用一下一维差分即可,即:

    d p [ i ] [ j ] + = ( d p [ i + 1 ] [ j ] + d p [ i ] [ j − 1 ] − d p [ i + 1 ] [ j − 1 ] ) dp[i][j] += (dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]) dp[i][j]+=(dp[i+1][j]+dp[i][j1]dp[i+1][j1])

查询:

直接输入 l , r l,r l,r ,输出 d p [ l ] [ r ] dp[l][r] dp[l][r] 即可。


C o d e Code Code

#include<bits/stdc++.h>
using namespace std;

#define int long long 
int n, q;
const int m = 1000000;
const int maxn = 5005;
int a[maxn];
int dp[maxn][maxn];
int cnt[4000005];

signed main ()
{
	scanf ("%lld %lld", &n, &q);
	for (int i = 1; i <= n; i++)
	{
		scanf ("%lld", &a[i]);
	} 
	for (int i = 1; i <= n; i++)
	{
		for (int j = i + 1; j <= n; j++)
		{
			if (0 <= m - a[j] - a[i] and m - a[i] - a[j] <= 2 * m) dp[i][j] = cnt[m - a[i] - a[j]];
			cnt[a[j] + m]++;
		}
		for (int j = i + 1; j <= n; j++) cnt[a[j] + m]--;
	}
	for (int len = 3; len <= n; len++)
	for (int i = 1; i + len - 1 <= n; i++)
	{
		int j = i + len - 1;
		dp[i][j] += (dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]);
	}
	while (q--)
	{
		int l, r;
		scanf ("%lld %lld", &l, &r);
		printf ("%lld\n", dp[l][r]);
	}
	return 0;
}

若有排版等错误 烦请管理员斧正 感激不尽!!

posted @ 2022-03-25 07:25  pldzy  阅读(20)  评论(0)    收藏  举报