Description
给定平面上 (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();}