测试地址:虔诚的墓主人
做法:本题需要用到线段树+离散化+组合数。
首先我们可以先将常青树的横纵坐标离散化,可是能成为十字架中心的墓地数量还是可能有个,这要怎么办呢?
我们可以从下到上对于每一行,维护十字架中心在这一行的一段连续的墓地中的贡献。注意到我们要求的是:
在同一段连续的墓地中,和都相同,那么我们只需要统计这一段中的和就可以了。因为我们从下到上枚举行,所以可能会有单点修改的情况,而单点修改区间求和显然可以用线段树或树状数组来做,这里为了练手就写了线段树。
因为点的数量只有,所以上面的连续段的数量也是的数量级,至于组合数可以预处理出来,那么总的复杂度就是,可以通过此题。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=(ll)2147483647+(ll)1;
int n,m,w,k,tot0,tot,totx[100010]={0},toty[100010]={0},down[100010]={0};
ll C[100010][11]={0},seg[400010]={0};
struct point
{
int now,a,b;
}p[100010];
bool cmp1(point a,point b)
{
if (a.a!=b.a) return a.a<b.a;
return a.b<b.b;
}
bool cmp2(point a,point b)
{
if (a.b!=b.b) return a.b<b.b;
return a.a<b.a;
}
void init()
{
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=w;i++)
scanf("%d%d",&p[i].a,&p[i].b);
scanf("%d",&k);
sort(p+1,p+w+1,cmp1);
tot0=0;
for(int i=1;i<=w;i++)
{
if (i==1||p[i].a!=p[i-1].a) ++tot0;
p[i].now=tot0;
}
for(int i=1;i<=w;i++)
p[i].a=p[i].now;
sort(p+1,p+w+1,cmp2);
tot=0;
for(int i=1;i<=w;i++)
{
if (i==1||p[i].b!=p[i-1].b) ++tot;
p[i].now=tot;
}
for(int i=1;i<=w;i++)
{
p[i].b=p[i].now;
totx[p[i].a]++,toty[p[i].b]++;
}
C[0][0]=1;
for(int i=1;i<=w;i++)
{
C[i][0]=1;
for(int j=1;j<=k;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
void pushup(int no)
{
seg[no]=seg[no<<1]+seg[no<<1|1];
}
void modify(int no,int l,int r,int x,ll d)
{
if (l==r) {seg[no]=d;return;}
int mid=(l+r)>>1;
if (x<=mid) modify(no<<1,l,mid,x,d);
else modify(no<<1|1,mid+1,r,x,d);
pushup(no);
}
ll query(int no,int l,int r,int s,int t)
{
if (s>t) return 0;
if (l>=s&&r<=t) return seg[no];
ll ans=0;
int mid=(l+r)>>1;
if (s<=mid) ans=(ans+query(no<<1,l,mid,s,t))%mod;
if (t>mid) ans=(ans+query(no<<1|1,mid+1,r,s,t))%mod;
return ans;
}
void work()
{
ll ans=0;
int nowx=0;
for(int i=1;i<=tot;i++)
{
int lft=0,last=0;
for(int j=nowx+1;j<=nowx+toty[i];j++)
{
ans=(ans+C[lft][k]*C[toty[i]-lft][k]%mod*query(1,1,tot0,last+1,p[j].a-1)%mod)%mod;
down[p[j].a]++;
modify(1,1,tot0,p[j].a,C[down[p[j].a]][k]*C[totx[p[j].a]-down[p[j].a]][k]%mod);
last=p[j].a;
lft++;
}
nowx+=toty[i];
}
printf("%lld",ans);
}
int main()
{
init();
work();
return 0;
}