Luogu2154 虔诚的墓主人

Description

link

给定平面上 (n) 个点和一个整数 (k)

求平面上有多少个点满足正上,正下,正左,正右都有 (k) 个点

如果某一方向上有大于 (k) 个点,那么需要计算选择 (k) 个的方案

方案数对 (2147483648) 取模

(nle 10^5 k le 10)

Solution

如果你看到原题面,那就加一句,这题要离散化

这题上来先观察一下,如果满足有大于 (k) 个点,就是个组合计数,乘一下组合数就好了

这里要注意的是要按照杨辉的方法 (dp) 算组合数,这个模数不是质数,逆元不行

其实答案就是

[suminom l k inom r k inom u k inom d k ]

这里的 (l r u d) 表示的是在点的方位的树的数量

这是一句废话,但是如果没思考是想不到的

先把所有的已知点按 (x)(y) 为第一第二关键字排序

然后我们对于 (x) 值相同的点

上下的树数可以拿桶来求,已知当前点坐标的左右的也可以用桶

然后我们发现这里需要求出来区间内 (suminom l k inom r k) 的值

上树状数组维护一下即可

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	#define mp make_pair
	#define f first
	#define s second
 	const int N=5e5+10,mod=2147483648;
	int n,m,w,k,x[N],y[N],a[N],b[N],tx,ty,ans; 
	struct BIT{
		int c[N];
		inline int lowbit(int x){return x&(-x);}
		inline int ask(int x){int res=0; for(;x;x-=lowbit(x)) (res+=c[x])%=mod; return res;}
		inline void add(int x,int d){for(;x<=w;x+=lowbit(x)) (c[x]+=d)%=mod; return ;}
	}T;
	int cx[N],cy[N];
	pair<int,int> p[N];
	#define C(x,y) cl[x][y]
	int u,d,l[N],r,cl[N][25];
	signed main()
	{
		n=read(); m=read(); w=read();
		for(int i=1;i<=w;++i) a[i]=x[i]=read(),b[i]=y[i]=read();
		k=read(); cl[0][0]=1; 
		for(int i=1;i<=w;++i) 
		{
			cl[i][0]=1; for(int j=1;j<=k;++j) cl[i][j]=(cl[i-1][j]+cl[i-1][j-1])%mod;
		}
		sort(a+1,a+w+1); sort(b+1,b+w+1);
		for(int i=1;i<=w;++i) x[i]=lower_bound(a+1,a+w+1,x[i])-a,++cx[x[i]];
		for(int i=1;i<=w;++i) y[i]=lower_bound(b+1,b+w+1,y[i])-b,++cy[y[i]];
		for(int i=1;i<=w;++i) p[i]=mp(x[i],y[i]);
		sort(p+1,p+w+1); 
		for(int i=1;i<w;++i)
		{
			if(p[i].f==p[i-1].f) d++; else d=1;
			u=cx[p[i].f]-d; 
			if(u) 
			{
				ans+=cl[d][k]*cl[u][k]%mod*((T.ask(p[i+1].s-1)-T.ask(p[i].s)+mod)%mod)%mod;
				ans%=mod; 
			}
			l[p[i].s]++;
			int s1=C(l[p[i].s],k)*C(cy[p[i].s]-l[p[i].s],k)%mod;
			int s2=((T.ask(p[i].s)-T.ask(p[i].s-1))%mod+mod)%mod;
			T.add(p[i].s,((s1-s2)%mod+mod)%mod);
		}
		printf("%lld
",(ans%mod+mod)%mod);
		return 0;
	}
}
signed main(){return yspm::main();}
原文地址:https://www.cnblogs.com/yspm/p/12827813.html