CF627E Orchestra 题解

题目传送门:CF627E Orchestra

这题好牛啊,可能只是我菜 /ll。

首先我们可以枚举 \(i,j\) 确定矩形的上下界,考虑如何快速计算贡献。

首先,我们将所有的点按照列为第一关键字,行为第二关键字排序,那么在枚举 \(i\) 时,就可以将所有行在 \([i,r]\) 的点,加入链表,那么每个点的贡献来自于它\(k-1\) 个点的列,而这个贡献相当于就是矩形左测可以在这个位置和上一个位置之间,右端点在它后 \(k-1\) 个点的列到 \(c\) 之间,乘法原理很好计算,那么我们需要动态维护每个点后 \(k-1\) 的位置即可。

考虑倒序枚举 \(j\),容易发现我们需要删去链表中的一些点,而这些点删去会使得左侧 \(k-1\) 个位置的右侧 \(k-1\) 的位置向右移动一位,暴力维护贡献增减即可,还要注意这个删去位置的右侧第一个的贡献也改变了,一个一个点暴力删除即可。

最后复杂度 \(O(r^2k)\),这里 \(r,c,n\) 同阶。

注意一些边界和清空,这题细节还是比较多的,代码一坨。

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=3010;
inline int read(){
	char c=getchar();
	int f=1,ans=0;
	while(c<48||c>57) f=(c==45?f=-1:1),c=getchar();
	while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();
	return ans*f;
}
int n,m,k,len;
struct node{
	int x,y;
	bool operator <(const node &xx) const{
		if (y==xx.y) return x<xx.x;
		return y<xx.y;
	}
}a[N];
int L[N],R[N],vis[N],cnt[N],c[N];
vector<int>b[N];
main(){
	n=read(),m=read(),len=read(),k=read();
	for (int i=1;i<=len;i++) a[i]={read(),read()};
	sort(a+1,a+len+1);
	int ans=0;
	for (int i=1;i<=n;i++){
		for (int i=0;i<=len+1;i++) L[i]=R[i]=vis[i]=c[i]=0;
		for (int i=1;i<=m;i++) cnt[i]=0;
		for (int i=1;i<=n;i++) b[i].clear();
		int last=0;
		for (int j=1;j<=len;j++) 
			if (i<=a[j].x){
				cnt[a[j].y]++;
				if (cnt[a[j].y]==1) vis[j]=1;
				L[j]=last;
				R[last]=j;
				b[a[j].x].push_back(j);
				last=j; 
			} 
		R[last]=len+1,L[len+1]=last;
		int x=0,sum=0;
		while(x!=len+1){
			int y=x;
			int tmp=k-1;
			while(tmp--){
				if (y==len+1) break;
				y=R[y];
			}
			c[x]=y;
			if (y!=len+1&&vis[x]) sum+=(m-a[y].y+1)*(a[x].y-a[L[x]].y);
			x=R[x];
		} 
		for (int j=n;j>=i;j--){
			ans+=sum;
			for (auto x:b[j]){
				if (c[x]!=len+1&&vis[x]) sum-=(m-a[c[x]].y+1)*(a[x].y-a[L[x]].y);
				int y=x;
				int tmp=k-1;
				while(tmp--){
					y=L[y];
					if (y==0) break;
					if (c[y]!=len+1){
						if (vis[y]) sum-=(m-a[c[y]].y+1)*(a[y].y-a[L[y]].y);
						c[y]=R[c[y]];
						if (c[y]!=len+1&&vis[y]) sum+=(m-a[c[y]].y+1)*(a[y].y-a[L[y]].y); 
					}
				}
				if (R[x]!=len+1&&vis[R[x]]){
					int xx=R[x];
					if (c[xx]!=len+1&&vis[xx]){
						sum-=(m-a[c[xx]].y+1)*(a[xx].y-a[L[xx]].y);
						sum+=(m-a[c[xx]].y+1)*(a[xx].y-a[L[x]].y);
					}
				} 
				L[R[x]]=L[x];
				R[L[x]]=R[x];
			}
		}
	}
	cout <<ans;
	return 0;
}
posted @ 2026-01-06 00:00  OTn53_qwq  阅读(7)  评论(0)    收藏  举报