刚回学校发现沉睡了一寒假的教学楼突然复活了,整栋教学楼灯火通明,到处都充满了开学考试的气氛,作为脑部重伤在院逃过了开学考的蒟蒻,还是感到庆幸
不管怎样
首先预祝大家开学考试愉快(~ ̄▽ ̄)~
Problem
题目描述
一块N×M的矩形,由树和墓地构成
一块墓地的价值是指以这块墓地为中心的十字架的数目。一个十字架定义为中间是墓地,墓地的正上、正下、正左、正右都有恰好k棵树。
求所有墓地的虔诚度总和是多少。
输入格式:
第一行N和M,表示公墓的宽和长,因此这个矩形公墓共有(N+1) ×(M+1)个格点,左下角的坐标为(0, 0),右上角的坐标为(N, M)
第二行W,表示矩形中树的个数。
第三行起共W行,每行表示一棵常青树的坐标,没有两棵常青树拥有相同的坐标。
最后一行包含一个正整数k。
输入输出样例
输入样例:
5 6
13
0 2
0 3
1 2
1 3
2 0
2 1
2 4
2 5
2 6
3 2
3 3
4 3
5 2
2
输出样例:
6
说明
图中,以墓地(2, 2)和(2, 3)为中心的十字架各有3个,即它们的虔诚度均为3。其他墓地的虔诚度为0。
数据范围:
30%:1 ≤ N, M ≤ 1,000。
60%:1 ≤ N, M ≤ 1,000,000。
100%:1 ≤ N, M ≤ 1,000,000,000,0 ≤ xi ≤ N,0 ≤ yi ≤ M,1 ≤ W ≤ 100,000,1 ≤ k ≤ 10。
存在50%的数据,满足1 ≤ k ≤ 2。
存在25%的数据,满足1 ≤ W ≤ 10000。
Solution
看到数据, n,m≤1e9,w≤1e5 n , m ≤ 1 e 9 , w ≤ 1 e 5
模拟基础算法 O(nm) O ( n m ) ,30分暴力
明显对树进行操作,并且坐标离散化
每个点的贡献是 Ck上面的点数⋅Ck左...⋅Ck下...⋅Ck右... C 上 面 的 点 数 k · C 左 . . . k · C 下 . . . k · C 右 . . . k
但如果对地图上所有点都暴力进行统计的话,就是楼上的那个30分暴力算法
但是,想到,有一些墓是注定不会有贡献的,比如说上下左右只要有一方没有点,此点贡献即为0,这就是进行离散化的依据,因为那些剩下的墓都是废的
到了这一步,我们还剩下一个大小不超过 w×w w × w 的方格,且每一行每一列都有一个或以上的点
再想到,对于一些连续存在的墓,我们可以一起计算,最简单的就是一横行中相近两点之间的墓(就是一行中被相邻两点夹着的一条线段)可以连续计算
考虑到 ∑Ck上...⋅Ck左...⋅Ck下...⋅Ck右... ∑ C 上 . . . k · C 左 . . . k · C 下 . . . k · C 右 . . . k 中各个点的 Ck左...⋅Ck右... C 左 . . . k · C 右 . . . k 相等
所以答案变为 Ck左...⋅Ck右...∑Ck上...⋅Ck下... C 左 . . . k · C 右 . . . k ∑ C 上 . . . k · C 下 . . . k
如果我们从左往右扫的话,我们就可以轻松统计出 Ck左...⋅Ck右... C 左 . . . k · C 右 . . . k
所以我们只要快速求解 ∑Ck上...⋅Ck下... ∑ C 上 . . . k · C 下 . . . k 即可,容易联想到树状数组,那么我们只用在每一行从左往右扫的基础上从下往上扫,在每遇到一个点的时候更新这一竖行的值即可
还有一些细节,比如说预处理组合数(用递推更配哦),最终答案位与2147483647(消除符号差异)
详见代码(虽然同机房神犇都说蒟蒻的代码很丑)
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register
#define cl(x) memset(x,0,sizeof(x))
#define lowbit(x) ((-(x))&(x))
template <typename _Tp> inline void read(_Tp&x){
rg char c11=getchar(),ob=0;x=0;
while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return ;
}
const int N=100500,K=12;const ll p=2147483648;
struct node{
ll x,y;
bool operator < (const node aa) const {if(y==aa.y)return x<aa.x;return y<aa.y;}
}t[N];
int c[N][K];
ll b[N],X[N],Y[N];
int x[N],xx[N],y[N],yy[N];
int n,m,w,wx,wy,k;
ll ans=0;
void pre_c(){
cl(c);
c[0][0]=1;
for(rg int i=1;i<=w;++i){
c[i][0]=1;
for(rg int j=1;j<=min(k,i);++j)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
}
}
inline void update(int x,ll y){for(;x<=wx;x+=lowbit(x))b[x]+=y;return ;}
inline ll query(int x){
ll ans=0;
for(;x;x-=lowbit(x))ans+=b[x];
return ans;
}
int main(){
read(n),read(m);
read(w);
for(rg int i=1;i<=w;++i)read(t[i].x),read(t[i].y),X[i]=t[i].x,Y[i]=t[i].y;
read(k);
sort(X+1,X+w+1);sort(Y+1,Y+w+1);
wx=unique(X+1,X+w+1)-X-1;
wy=unique(Y+1,Y+w+1)-Y-1;
for(rg int i=1;i<=w;++i){
t[i].x=lower_bound(X+1,X+wx+1,t[i].x)-X;
t[i].y=lower_bound(Y+1,Y+wy+1,t[i].y)-Y;
++x[t[i].x],++y[t[i].y];
}
sort(t+1,t+w+1);
pre_c();
for(rg int i=1;i<=w;++i){
++xx[t[i].x],++yy[t[i].y];
update(t[i].x,
c[xx[t[i].x]][k] * c[x[t[i].x]-xx[t[i].x]][k] -
c[xx[t[i].x]-1][k] * c[x[t[i].x]-xx[t[i].x]+1][k]);
if(t[i-1].y==t[i].y){
ans=(ll)((ans+(query(t[i].x-1)-query(t[i-1].x))
*c[y[t[i].y]-yy[t[i].y]+1][k]%p*c[yy[t[i].y]-1][k]%p)%p);
}
}
printf("%lld\n",ans&2147483647);
return 0;
}