8.5早做题感悟

来源:互联网 发布:java 线程池 等待队列 编辑:程序博客网 时间:2024/06/01 08:34

今天早上莫名看到一道非常有意思的题 
虔诚的墓主人 (SDOI 2009) 
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 

Sample Output 

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棵

题解 
对于每一块来说,其虔诚值应该为 C(u,k)*C(d,k)*C(l,k)*C(r,k) (u,d,l,r分别为这一块上下左右有多少棵树) 
如果要一个个枚举的话,时间复杂度为O(NM) 爆炸…… 
我们要仔细想想:哪些地方做了冗余的运算? 
不难发现:可能某一行或某一列没有树,但是我们还是计算了,浪费了很多时间 
那么,发现了这个,算法的优化应该就很清楚了: 
离散化坐标,将中间根本没用的东西直接扔掉,保证每一个我求的部分都有虔诚值 
不会离散化的同学,[戳这里](http://www.matrix67.com/blog/archives/108)#
此时的时间复杂度? O(w^2) 
还是T飞了……(话说相对于一开始的要好很多……) 
现在我们的目标就变成了,要把时间复杂度降到 O(w log w)的级别 
还有什么其他特别的性质么? 
发现:同一行两棵树之间的 C(l,k)*C(r,k)相等 
所以,现在对于某一列,我只要求出各个C(u[i],k)*C(d[i],k)的和就行了 
怎么求和? 
用数据结构维护!——树状数组或线段树(建议树状数组,没必要用线段树,而且比较好写) 
那么时间复杂度就这么一步步地被我们降到了 O(w log w) 
最后还有一个小技巧: 
取模的时候常数复杂度太大,怎么降低? 
发现这里其实是对 2^31取模,就是INT_MAX+1取模 
我们只要让它溢出int范围,最后答案&INT_MAX即可 
不必开long long一直取模……(这样可能还会T,常数太大)

原创粉丝点击