P2154 虔诚的墓主人 题解


P2154 虔诚的墓主人 题解

原题传送门

题意

\(n\times m\) 一个方格上给你 \(w\) 个点,求方格里每个点正上下左右各选 \(k\) 个点的方案数。

\(1 \le N, M \le 1,000,000,000,0 \le x_i \le N,0 \le y_i \le M,1 \le W \le 100,000,1 \le k \le 10\)

思路

首先看到 \(N,M\) 这么大,肯定要先离散化一下。

然后考虑怎么求方案数。

我们先对离散化后的点排个序,然后考虑两个 \(x\) 相同的点 \(x,y1\)\(x,y2\) 之间的所有点的方案数。

显然是:

\[C_{y1\_UP}^{k}\times C_{y2\_DOWN}^{k}\times \sum_{y1

你们意会一下。

观察这个式子,\(C_{y1\_UP}^{k}\times C_{y2\_DOWN}^{k}\) 当前已知,可以用前缀和维护 \(\sum C_{l\_LEFT}^{k}\times C_{l\_RIGHT}^{k}\)

那么我们就开一个树状数组,维护前 \(i\) 行的 \(C_{l\_LEFT}^{k}\times C_{l\_RIGHT}^{k}\) 之和,每次碰到一个点 \(x,yy\) 时把当前行的影响清除,再令 \(yy\_LEFT+1,yy\_RIGHT-1\),再重新计入前缀和。

可以参考代码中 Solve 函数中变量 \(u\) 的求法。

时间复杂度 \(O(nlogn)\)

我这个菜鸡居然因为取模取错了调了两节课。

Code

#include 
#define _for(i,a,b) for(ll i=a;i<=b;++i)
#define for_(i,a,b) for(ll i=a;i>=b;--i)
#define ll long long
using namespace std;
const ll N=1e5+10,P=2147483648;
ll n,m,w,k,q[N],h[N],z[N],y[N],ans;
struct tree{ll x,y;}t[N];
inline ll rnt(){
	ll x=0,w=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*w;
}
namespace SZSZ{
	/*树状数组*/
	ll b[N];
	inline ll lowbit(ll x){return x&-x;}
	inline void UpDate(ll x,ll y){
		while(x<=w){
			b[x]=(b[x]+y)%P;
			x+=lowbit(x);
		}
		return;
	}
	inline ll Query(ll x){
        if(x==0)return 0;
		ll sum=0;
		while(x){
			sum=(sum+b[x])%P;
			x-=lowbit(x);
		}
		return sum;
	}
}
namespace LISAN{
	/*离散化*/
	vectorxx,yy;
	inline bool cmp(tree a,tree b){
		if(a.x==b.x)return a.y=k&&h[t[i].x]-q[t[i].x]>=k){
				ll up=c[q[t[i].x]][k];
				ll dn=c[h[t[i].x]-q[t[i].x]][k];
				ll ri=SZSZ::Query(t[i+1].y-1)-SZSZ::Query(t[i].y);
				ans+=((up*dn+P)%P*ri+P)%P;
                ans%=P;
			}
			ll u=((c[z[t[i].y]][k]*c[y[t[i].y]-z[t[i].y]][k]+P)%P-(SZSZ::Query(t[i].y)-SZSZ::Query(t[i].y-1)+P)%P+P)%P;
			SZSZ::UpDate(t[i].y,u);
		}
		return ans;
	}
}
int main(){
	n=rnt(),m=rnt(),w=rnt();
	_for(i,1,w){
		t[i].x=rnt(),t[i].y=rnt();
		LISAN::Add(t[i].x,t[i].y);
	}
	k=rnt();
	LISAN::LiSan();
	printf("%lld\n",SOLVE::Solve());
	return 0;
}
/*

*/