1. 程式人生 > >洛谷P1296 奶牛的耳語

洛谷P1296 奶牛的耳語

題目傳送門

隨機跳到的一道題,雖然確實挺水但是也不至於是紅題吧qwq,可能是因為資料過水導致一大片 n 2 n^2 暴力過了所以拉低了評分,雖然以這道題的資料範圍 n 2

n^2 應該被卡掉的。

簡述題意:給定一個序列和一個數 d d ,求無序數對 < i ,

j > <i,j> 的個數,滿足 a i
a j < = d |a_i-a_j|<=d

思路:先將給定的序列排序,然後放入一個佇列中,維護與隊首距離 < = d <=d 的數是哪些。當我們要加入一個數的時候,先將當前佇列中與新加入的數距離過遠的數出隊,同時更新答案,然後將新的數加入隊尾。因為我們已經將序列排好序了,所以需要出隊的數都在隊首,直接判斷即可。

考慮資料出隊時如何更新答案。我們佇列裡記錄的是比隊首大的、符合要求的數(一開始從小到大排序的話),因此答案只需要加上當前佇列裡的元素數量即可(隊首要去掉)。那麼比隊首小的符合要求的數會漏掉嗎?其實並不會,因為 < i , j > <i,j> < j , i > <j,i> 是相同的,所以這部分已經在之前計算過了。

這樣做的複雜度為 O ( n l o g n + n ) O(nlogn+n) ,過此題無壓力

最後,別被樣例坑了,輸入的資料是無序的,要記得排序(我就是這樣在一道紅題WA了兩次的QAQ,真的是天下最弱了)

貼程式碼

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100010;
int n,m,a[N],q[N],fp=1,rp;
long long ans;
int main()
{
	scanf("%d%d",&n,&m);ans=0;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+n+1);//千萬別忘了排序!!! 
	for(int i=1;i<=n;i++)
	{
		while(fp<=rp&&q[fp]+m<a[i])ans=ans+rp-fp,fp++;//將不合要求的隊首出隊,同時更新答案 
		q[++rp]=a[i];//將當前數入隊 
	}
	int t=rp-fp+1;ans=ans+(long long)t*(t-1)/2;//最後佇列裡會剩下一些數,別忘了處理 
	printf("%lld\n",ans);return 0;
}