題解:CF1119D Frets On Fire

shoot_down發表於2024-05-26

大水題。

首先,若區間內只有一根弦,不會對答案有貢獻。

我們思考如何對答案產生貢獻。我們知道,對於每一個 \(s_i\),都會產生一段 \(s_i+r-l\) 的連續序列,在對 \(s\) 陣列排序後,若每個 \(s_i+r-l \ge s_{i+1}\) 則答案為 \(s_n+r-(s_1+l)+1\)

若夠不到下一位呢?我們在 \(s_n+r-(s_1+l)+1\),上減去夠不到的位數即可。

過程的實現:我們先對 \(s\) 陣列排序,將 \(s_{i+1}-s_i \ge 2\)\(s_{i+1}-s_i\) 壓入 \(c\) 陣列中,對 \(c\) 排序,並且求其字首和陣列 \(sum\)。設 \(c\) 陣列長度為 \(m\)

對於詢問 \(l,r\),若 \(r-l\) 大於 \(c_m\),二分查詢 \(c\) 陣列中第一個大於 \(r-l\) 的數,\(c_x\)。夠不到的位數即為 sum[m]-sum[x-1]-ch*(m-x+1)。用 \(s_n+r-(s_1+l)+1\) 減去即可。反之,輸出 \(s_n+r-(s_1+l)+1\) 即可。

程式碼(講的很詳細了不放註釋了):

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;
int a[N],sum[N],c[N];
int n,m;
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+1+n);
	for(int i=2;i<=n;i++) {
		if(a[i]-a[i-1]>1) c[++m]=a[i]-a[i-1]-1;
	}
	sort(c+1,c+1+m);
	for(int i=1;i<=m;i++) sum[i]=sum[i-1]+c[i];
	int qu;
	cin>>qu;
	while(qu--){
		int l,r;
		cin>>l>>r;
		int ch=r-l,ans=a[n]+r-a[1]-l+1;
		if(ch<c[m]) {
			int w=upper_bound(c+1,c+1+m,ch)-c;
//			cout<<w<<'\n';
			int su=sum[m]-sum[w-1]-ch*(m-w+1);
			ans-=su;
		}
		cout<<ans<<' ';
	}
	return 0;
}

相關文章