P6006 [USACO20JAN]Farmer John Solves 3SUM G:二維前綴和

題目來源:[USACO20JAN]Farmer John Solves 3SUM G
題目大意:找出任意區間三個數加起來和爲0的個數。
一開始想N3N^3;後來用個桶想&N^2$,還是有問題。原來設i<j<k,或k<i<j都統計的很糊塗。
後來看題解才弄明白,設i<k<j,設sum[i][j]爲i爲起點,j爲終點的情況下滿足條件的個數,然後用二維前綴和維護,查詢用二維差分o(1)完成。
參考代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5005,M=1E6+5;
int n,q,t[2*M];
ll a[N],sum[N][N];
int work0(int l,int r){
	int cnt=0;
	for(int i=l;i<=r-2;i++)
		for(int j=i+1;j<=r-1;j++)
			for(int k=j+1;k<=r;k++)
				if(a[i]+a[j]+a[k]==0){
					cnt++;
				}
	return cnt;
}
void work(){
	
	for(int i=1;i<n;i++){//i<k<j,
		for(int j=i+1;j<=n;j++){//應該統計i,到j中間有多少 
			ll tmp=-a[i]-a[j];
			if(j>=i+2&&tmp+M<2*M&&tmp+M>=0){
				sum[i][j]=t[tmp+M];//這是算的從i到j 
			//	cout<<i<<" "<<j<<" "<<tmp<<" t"<<t[tmp+M]<<endl;
			}
			t[a[j]+M]++;
		}
		for(int j=i+1;j<=n;j++)t[a[j]+M]--;	
	}
	
	for(int i=1;i<=n;i++)	
		for(int j=1;j<=n;j++)
			sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];				
	return ;
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	work();
	for(int i=1;i<=q;i++){
		int l,r;
		scanf("%d%d",&l,&r);
		printf("%lld\n",sum[r][r]-sum[l-1][r]-sum[r][l-1]+sum[l-1][l-1]);	
	}
	
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章