虔诚的墓主人:组合数+数据结构

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。 所有数据满足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。 注意:”恰好有k颗树“,这里的恰好不是有且只有,而是从>=k的树中恰好选k棵

一定要看提示。。。不然看不懂样例

首先说一个奇技淫巧:模数很熟悉不对么?1e31诶,怎么办呢?

好多人的第一想法都是unsigned,麻烦了。因为在二进制下,它和普通int是完全一样的啊

我们只需要忽略二进制下的最高位就可以了,它在unsigned下表示1e32,在int下表示符号

用普通int,在结尾如果它负了,加上1<<31即可。其余全程自然溢出。

我喜欢做一些奇奇怪怪的比喻:

在同一行上的树,它们之间的地面有可能能贡献答案,我们管这篇区域叫做激光柱(不含树的位置)!

列上的也同理。那么在激光住的交点上就有对答案的贡献了。

*-------*-----*--------*

     1      2         3

*是树,那么这是3个不同的激光柱。

因为我们最后对于每块墓地都是上下左右的组合数乘起来。

然而对于每个横着的激光柱,它自己管辖的区域中左右乘积都一样,所以预处理它就好。竖着的同理。

64%算法:

暴力找出所有激光住,w log w

两层循环分别枚举所有横,竖的激光柱,看它们有没有交点,有就把组合数乘起来累加答案。w2

100%算法:

其实上一个算法的冗余很多,看一下下面的例子。

   *      *      *      *     *                                   1

   |      |      |       |      |                                   2

*-o----o---o-----o---o-------*                        3

   |      |      |       |      |                                  4

 *o----o---o-----o-*   |                                  5

   |      |      |       |     *                                   6

   *      *     *      *                                          7

*还是树,o是贡献答案的墓地

我们可以发现第3排和第5排很相似,纵然它们的横着的激光柱不同。

假如我们处理好了第2排的情况,往下再走一行,竖着的激光柱并没有改变。

所以上一行的情况,可以继承到下一行来,然后区间询问组合数的和,乘上横激光柱的组合数,累加答案即可。

假如往下走的过程中竖的激光柱改变了(遇到了新的,或者旧的结束了),那就改变前缀和,其实只是改了一位而已。

区间查询,单点修改。。。。。。树状数组。

没什么了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<map>
 4 using namespace std;
 5 int n,m,w,k,tim1[100005],mt1[100005],tim2[100005],mt2[100005],c[100005][11],nl,nr,ans;
 6 map<int,int>ma;int ref[800005],cnt,b[800005],cnt2,cnt3,cnt4=1,t[800005];
 7 void add(int p,int w){for(;p<=cnt2;p+=(p&-p))t[p]+=w;}
 8 int sum(int p,int aans=0){for(;p;p-=(p&-p))aans+=t[p];return aans;}
 9 struct tr1{
10     int x,y;
11     friend bool operator<(tr1 a,tr1 b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
12 }t1[100005];
13 struct tr2{
14     int x,y;
15     friend bool operator<(tr2 a,tr2 b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
16 }t2[100005];
17 struct line{int s,e,x,c;}l[100005];
18 struct row{
19     int s,e,y,c;
20     friend bool operator<(row a,row b){return a.y<b.y;}
21 }r[100005];
22 struct comm{
23     int x,w,y;
24     friend bool operator<(comm a,comm b){return a.y<b.y;}
25 }com[200005];
26 int main(){
27     scanf("%d%d%d",&n,&m,&w);c[1][1]=c[1][0]=1;
28     for(int i=1;i<=w;++i)scanf("%d%d",&t1[i].x,&t1[i].y),t2[i].x=t1[i].x,t2[i].y=t1[i].y;
29     sort(t1+1,t1+w+1);sort(t2+1,t2+w+1);scanf("%d",&k);
30     for(int i=2;i<=w;++i)for(int j=0;j<=k;++j)c[i][j]=c[i-1][j]+(j?c[i-1][j-1]:0);
31     for(int i=1;i<=w;++i)if(t1[i].x!=t1[i-1].x)tim1[i]=1;else tim1[i]=tim1[i-1]+1;
32     for(int i=1;i<=w;++i)if(t2[i].y!=t2[i-1].y)tim2[i]=1;else tim2[i]=tim2[i-1]+1;
33     for(int i=w;i;--i)if(t1[i].x!=t1[i+1].x)mt1[i]=1;else mt1[i]=mt1[i+1]+1;
34     for(int i=w;i;--i)if(t2[i].y!=t2[i+1].y)mt2[i]=1;else mt2[i]=mt2[i+1]+1;
35     for(int i=1;i<=w;++i)if(tim1[i]>=k&&mt1[i]>=k+1&&t1[i].y+1<=t1[i+1].y-1)
36         b[++cnt]=l[++nl].x=t1[i].x,l[nl].s=t1[i].y+1,l[nl].e=t1[i+1].y-1,l[nl].c=c[tim1[i]][k]*c[mt1[i]-1][k],com[(nl<<1)-1],com[nl<<1];
37     for(int i=1;i<=w;++i)if(tim2[i]>=k&&mt2[i]>=k+1&&t2[i].x+1<=t2[i+1].x-1)
38         r[++nr].y=t2[i].y,b[++cnt]=r[nr].s=t2[i].x+1,b[++cnt]=r[nr].e=t2[i+1].x-1,r[nr].c=c[tim2[i]][k]*c[mt2[i]-1][k];
39     sort(b+1,b+1+cnt);sort(r+1,r+1+nr);
40     for(int i=1;i<=cnt;++i)if(ma.find(b[i])==ma.end())ma[b[i]]=++cnt2,ref[cnt2]=b[i];
41     for(int i=1;i<=nl;++i)l[i].x=ma[l[i].x];
42     for(int i=1;i<=nr;++i)r[i].s=ma[r[i].s],r[i].e=ma[r[i].e];
43     for(int i=1;i<=nl;++i)com[++cnt3]={l[i].x,l[i].c,l[i].s},com[++cnt3]={l[i].x,-l[i].c,l[i].e+1};
44     sort(com+1,com+cnt3+1);
45     for(int i=1;i<=nr;++i){
46         while(cnt4<=cnt3&&r[i].y>=com[cnt4].y)add(com[cnt4].x,com[cnt4].w),cnt4++;
47         ans+=(sum(r[i].e)-sum(r[i].s-1))*r[i].c;
48     }
49     printf("%d",ans<0?ans+(1<<31):ans);
50 }
2300字英语作文
posted @ 2019-07-04 11:28  DeepinC  阅读(255)  评论(0编辑  收藏  举报