bzoj1227 [SDOI2009]虔诚的墓主人(组合公式+离散化+线段树)
1227: [SDOI2009]虔诚的墓主人
Time Limit: 5 Sec Memory Limit: 259 MB
Submit: 803 Solved: 372
[Submit][Status][Discuss]
Description
小W 是一片新造公墓的管理人。公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地。当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地。为了体现自己对主的真诚,他们希望自己的墓地拥有着较高的虔诚度。一块墓地的虔诚度是指以这块墓地为中心的十字架的数目。一个十字架可以看成中间是墓地,墓地的正上、正下、正左、正右都有恰好k 棵常青树。小W 希望知道他所管理的这片公墓中所有墓地的虔诚度总和是多少
Input
第一行包含两个用空格分隔的正整数N 和M,表示公墓的宽和长,因此这个矩形公墓共有(N+1) ×(M+1)个格点,左下角的坐标为(0, 0),右上角的坐标为(N, M)。第二行包含一个正整数W,表示公墓中常青树的个数。第三行起共W 行,每行包含两个用空格分隔的非负整数xi和yi,表示一棵常青树的坐标。输入保证没有两棵常青树拥有相同的坐标。最后一行包含一个正整数k,意义如题目所示。
Output
包含一个非负整数,表示这片公墓中所有墓地的虔诚度总和。为了方便起见,答案对2,147,483,648 取模。
Sample Input
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
Sample Output
HINT
图中,以墓地(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。
【思路】
组合公式+离散化+区间查询&单点修改。
如果设每一个空格左右上下各有的树之数目为left[][],right[][],up[][],down[][],则答案为

考虑到nm很大,这里我们先进行离散化,离散化之后时间复杂度为O(ww)。
考虑y同的两棵相邻的树(中间为空格)且x分别为ab,我们统计夹在中间的空格的分数,则为

前两项相同,因此只需要统计ab区间内的C之积即可,可以用线段树在O(logn)的时间内完成。
具体操作:
依次扫描每一棵树:
如果与前一棵树同y则累计答案。
维护cy表示当前y扫描过的树之数目。
维护cx[]表示x被扫描过的树之数目。
维护线段树。
需要注意的是n在线段树中定义为离散后x的最大下标。
【代码】
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long LL;
const int maxn = +;
const LL MOD = 2147483648LL;
struct Node{
int x,y;
bool operator<(const Node& rhs) const{
return y<rhs.y || (y==rhs.y && x<rhs.x);
}
}nodes[maxn]; int read() {
char c=getchar();
while(!isdigit(c)) c=getchar();
int x=;
while(isdigit(c)) {
x=x*+c-'';
c=getchar();
}
return x;
}
//线段树相关
//+单点修改+区间求和
LL sumv[*maxn];
int v; LL d;
void update(int u,int L,int R) {
int lc=u*,rc=lc+;
if(L==R) {
sumv[u]=d;
}
else {
int M=L+(R-L)/;
if(v<=M) update(lc,L,M);
else update(rc,M+,R);
sumv[u]=sumv[lc]+sumv[rc];
}
}
int y1,y2;
LL query(int u,int L,int R) {
int lc=u*,rc=lc+;
if(y1<=L && R<=y2) {
return sumv[u];
}
else {
int M=L+(R-L)/;
LL res=;
if(y1<=M) res += query(lc,L,M);
if(M<y2) res += query(rc,M+,R);
res %= MOD;
return res;
}
}
//组合函数相关
LL C[maxn][];
void get_C(int n) {
C[][]=;
for(int i=;i<=n;i++) {
C[i][]=C[i][i]=;
for(int j=;j<=;j++)
C[i][j]=(C[i-][j]+C[i-][j-])%MOD;
}
} int cx[maxn],sumx[maxn],sumy[maxn];
int hash[*maxn],x[maxn],y[maxn];
int n,m,w,k; int main() {
n=read(),m=read(),w=read();
get_C(w);
int p=;
FOR(i,,w) {
x[i]=read(),y[i]=read();
hash[p++]=x[i],hash[p++]=y[i];
}
p--;
k=read();
//离散化坐标
sort(hash+,hash+p+);
p=unique(hash+,hash+p+)-hash; p--;
n=;
FOR(i,,w) {
x[i]=lower_bound(hash+,hash+p+,x[i])-hash;
y[i]=lower_bound(hash+,hash+p+,y[i])-hash;
n=max(n,x[i]); //n用于线段树表示最大x下标
sumx[x[i]]++,sumy[y[i]]++;
nodes[i]=(Node){x[i],y[i]};
}
sort(nodes+,nodes+w+);
//扫描每一棵树
LL ans=,cy=;
FOR(i,,w) {
int r=nodes[i].x,c=nodes[i].y;
if(i> && c==nodes[i-].y) {
y1=nodes[i-].x+,y2=nodes[i].x-;
if(y1<=y2) ans = (ans+C[cy][k]*C[sumy[c]-cy][k]%MOD*query(,,n)%MOD)%MOD;
cy++;
}
else cy=; cx[r]++;
v=r; d=C[cx[r]][k]*C[sumx[r]-cx[r]][k]%MOD;
update(,,n);
}
printf("%lld\n",ans);
return ;
}
bzoj1227 [SDOI2009]虔诚的墓主人(组合公式+离散化+线段树)的更多相关文章
- BZOJ1227 SDOI2009 虔诚的墓主人【树状数组+组合数】【好题】*
BZOJ1227 SDOI2009 虔诚的墓主人 Description 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地. ...
- [BZOJ1227][SDOI2009]虔诚的墓主人 组合数+树状数组
1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec Memory Limit: 259 MBSubmit: 1433 Solved: 672[Submit][Stat ...
- [bzoj1227] [SDOI2009]虔诚的墓主人
终于填上了这个万年巨坑....从初二的时候就听说过这题...然后一直不敢写QAQ 现在感觉也不是很烦(然而我还是写麻烦了 离散化一波,预处理出组合数什么的.. 要维护对于当前行,每列上方和下方节点凑出 ...
- BZOJ1227 [SDOI2009]虔诚的墓主人 【树状数组】
题目 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地.为 ...
- bzoj1227: [SDOI2009]虔诚的墓主人(树状数组,组合数)
传送门 首先,对于每一块墓地,如果上下左右各有$a,b,c,d$棵树,那么总的虔诚度就是$C_k^a*C_k^b*C_k^c*C_k^d$ 那么我们先把所有的点都给离散,然后按$x$为第一关键字,$y ...
- 【BZOJ1227】[SDOI2009]虔诚的墓主人(线段树)
[BZOJ1227][SDOI2009]虔诚的墓主人(线段树) 题面 BZOJ 洛谷 题解 显然发现答案就是对于每一个空位置,考虑上下左右各有多少棵树,然后就是这四个方向上树的数量中选\(K\)棵出来 ...
- Bzoj 1227: [SDOI2009]虔诚的墓主人 树状数组,离散化,组合数学
1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec Memory Limit: 259 MBSubmit: 895 Solved: 422[Submit][Statu ...
- bzoj1227 P2154 [SDOI2009]虔诚的墓主人
P2154 [SDOI2009]虔诚的墓主人 组合数学+离散化+树状数组 先看题,结合样例分析,易得每个墓地的虔诚度=C(正左几棵,k)*C(正右几棵,k)*C(正上几棵,k)*C(正下几棵,k),如 ...
- luoguP2154 [SDOI2009]虔诚的墓主人
SDOI2009虔诚的墓主人 喜闻乐见,我终于把此题读懂了..所以可以写了. 其实就是让我们求有多少个十字架 一个十字架的定义为中间有一个空地 周围4个正方向都有k棵树. 不难想到nm的暴力 我们预处 ...
随机推荐
- C#语法糖之开篇
本人虽然大学不是学的计算机但是对于IT行业的热爱,依然决然进军IT行业了,自从踏进这个行业到现在也已经3年多了,从去年开发通过网上 了解博客园后深深的爱上这儿了,这里有很多牛人,通过拜读他们的代码,让 ...
- ^(bitwise exclusive Or).
一个数,进行异或同一个数两次,将得到原来的数,例如: 6 ^ 4 ^ 4 = 6; 0000-0000-0000-0110 ^ 0000-0000-0000-0100 ---------------- ...
- 嵌入式css样式,写在当前的文件中
现在有一任务,把下面的“超酷的互联网”.“服务及时贴心”.“有趣易学”这三个短词文字字号修改为18px. 如果用内联式css样式的方法进行设置将是一件很头疼的事情(为每一个<span>标签 ...
- Linux系统下分割tomcat日志
在Linux系统下,tomcat日志catalina.out并不会像window系统下,按日期进行重写备份,因此在Linux系统下会造成日志文件过大的情况,本文介绍采用 cronolog工具进行如在w ...
- php实现返回上一页的功能的3种有效方法
php实现返回上一页的功能的3种有效方法 header(location:你的上一页的路径); // 注意这个函数前不能有输出 header(location:.getenv("HT ...
- 史上最强NDK入门项目实战
目标: 利用NDK生成SO库,使用SO库进行JNI调用,在Android sdcard创建文件并写入数据. 工具: NDK1.5 R1, android SDK1.5 R1, SDCARD, Ecli ...
- 2014/09/30 Learning Note
Vbird Linux: Vim Learning: http://linux.vbird.org/linux_basic/0310vi.php Bash Shell: http://linux.vb ...
- Python中几种数据结构的整理,列表、字典、元组、集合
列表:shoplist = ['apple', 'mango', 'carrot', 'banana']字典:di = {'a':123,'b':'something'}集合:jihe = {'app ...
- C++函数重载遇到了函数默认参数情况
一.C++中的函数重载 什么是函数重载? 我的理解是: (1)用一个函数名定义不同的函数: (2)函数名和不同参数搭配时函数会有不同的含义: 举例说明: #include <stdio.h> ...
- ACM竞赛常用STL(一)
全排列函数next_permutation STL 中专门用于排列的函数(可以处理存在重复数据集的排列问题) 头文件:#include <algorithm> using namespac ...