P6006 USACO 3SUM G

看题我想到了\(n^2\)预处理\(O(1)\)回答,然后开桶,想到这里发现不会了,\(n^3q\)暴力相信大家都会吧

考虑弱化,\(f[i][j]\)表示区间\([l,r]\)中满足\(k\in(l,r),a[k]+a[l]+a[r]=0的k的数量\),我们可以枚举左右端点开桶,\(n^2预处理f\)

但本题最后要求的是:在一段区间内,左右端点不强制选的方案数

考虑先求出\(s[l][r]\)表示左端点在\([1,l]\)内,右端点在\([1,r]\)内方案数,这就是\(f\)的二维前缀和

#include<cstdio>
#define maxn 5001
#define K 1000000
#define ll long long
using namespace std;
int n,q,a[maxn],cnt[2*K+1];
ll s[maxn][maxn];
int main(){
	scanf("%d%d",&n,&q);
	for(int i = 1;i <= n;i++)
	{scanf("%d",&a[i]);a[i] += K;}
	for(int i = 1;i <= n;i++){
		for(int j = i+1;j <= n;j++){
			if(j > i+1){
				if(a[i] + a[j] <= K*3 && a[i]+a[j] >= K)
					s[i][j] = cnt[K*3 - a[i] - a[j]];}
			cnt[a[j]] ++;
		}
		for(int j = i+1;j <= n;j++)
		cnt[a[j]] --;
	}
	for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j)
            s[i][j] += s[i-1][j]+s[i][j-1]-s[i-1][j-1];
            int l,r;
            while(q--){
            	scanf("%d%d",&l,&r);
            	printf("%lld\n", s[r][r]-s[l-1][r]-s[r][l-1]+s[l-1][l-1]);
			}
}	
posted @ 2020-08-09 08:20  INFP  阅读(117)  评论(0编辑  收藏  举报