Bzoj 1227: [SDOI2009]虔诚的墓主人 树状数组,离散化,组合数学

1227: [SDOI2009]虔诚的墓主人

Time Limit: 5 Sec  Memory Limit: 259 MB
Submit: 895  Solved: 422
[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

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

Sample Output

6

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。

 

Source

黄学长的题解: http://hzwer.com/1941.html

 

 我的丑陋的代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define MAXW 100010
 4 #define MOD 2147483648
 5 int xx[MAXW],yy[MAXW],W,K,down[MAXW],l[MAXW],h[MAXW];
 6 long long C[MAXW][12],BIT[MAXW];
 7 struct node
 8 {
 9     int x,y;
10 }p[MAXW];
11 int read()
12 {
13     int s=0,fh=1;char ch=getchar();
14     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
15     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
16     return s*fh;
17 }
18 bool cmp(node a,node b)
19 {
20     if(a.y==b.y)return a.x<b.x;
21     return a.y<b.y;
22 }
23 void GetC()
24 {
25     int i,j;
26     C[0][0]=1;
27     for(i=1;i<=W;i++)
28     {
29         C[i][0]=1;
30         for(j=1;j<=min(K,i);j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
31     }
32 }
33 int lowbit(int o){return o&(-o);}
34 long long Sum(int x)
35 {
36     long long sum=0;
37     while(x>0)
38     {
39         sum+=BIT[x];
40         x-=lowbit(x);
41     }
42     return sum;
43 }
44 void Add(int x,int add)
45 {
46     while(x<=W)
47     {
48         BIT[x]+=add;
49         x+=lowbit(x);
50     }
51 }
52 int main()
53 {
54     int n,m,i,cx,cy,left,wx,wy,wx1;
55     long long sum,s1,s2,add;
56     n=read();m=read();
57     W=read();
58     for(i=1;i<=W;i++){p[i].x=read();p[i].y=read();xx[i]=p[i].x;yy[i]=p[i].y;}
59     sort(xx+1,xx+W+1);
60     sort(yy+1,yy+W+1);
61     cx=unique(xx+1,xx+W+1)-(xx+1);
62     cy=unique(yy+1,yy+W+1)-(yy+1);
63     for(i=1;i<=W;i++)
64     {
65         l[lower_bound(xx+1,xx+cx+1,p[i].x)-(xx+1)+1]++;//统计每一列的个数.
66         h[lower_bound(yy+1,yy+cy+1,p[i].y)-(yy+1)+1]++;//统计每一行的个数.
67     }
68     K=read();
69     sort(p+1,p+W+1,cmp);//先按y从小到大排序,y相等按x从小到大排序.(离散化)
70     memset(BIT,0,sizeof(BIT));
71     left=0;//每个点左边的点的个数.
72     sum=0;
73     GetC();//预处理组合数.
74     memset(down,0,sizeof(down));//每个点下方的点的个数.
75     for(i=1;i<=W;i++)
76     {
77         if(i!=1&&p[i].y==p[i-1].y)
78         {
79             left++;
80             wx=lower_bound(xx+1,xx+cx+1,p[i].x)-(xx+1);
81             wy=lower_bound(yy+1,yy+cy+1,p[i].y)-(yy+1);
82             wx1=lower_bound(xx+1,xx+cx+1,p[i-1].x)-(xx+1);
83             wx++;wy++;wx1++;
84             s1=(Sum(wx-1)-Sum(wx1))%MOD;
85             s2=(C[left][K]*C[h[wy]-left][K])%MOD;
86             sum=(sum+(s1*s2)%MOD)%MOD;
87         }
88         else left=0;
89         wx=lower_bound(xx+1,xx+cx+1,p[i].x)-(xx+1);
90         wx++;down[wx]++;
91         add=(C[down[wx]][K]*C[l[wx]-down[wx]][K]-C[down[wx]-1][K]*C[l[wx]-down[wx]+1][K])%MOD;
92         Add(wx,add);
93     }
94     while(sum<0)sum+=MOD;
95     printf("%lld",sum);
96     return 0;
97 }
View Code

 

你可能感兴趣的:(Bzoj 1227: [SDOI2009]虔诚的墓主人 树状数组,离散化,组合数学)