P2154 虔诚的墓主人 题解

原题传送门

题意

在 \(n\times m\) 一个方格上给你 \(w\) 个点,求方格里每个点正上下左右各选 \(k\) 个点的方案数。

\(1 \le N, M \le 1,000,000,000,0 \le x_i \le N,0 \le y_i \le M,1 \le W \le 100,000,1 \le k \le 10\)。

思路

首先看到 \(N,M\) 这么大,肯定要先离散化一下。

然后考虑怎么求方案数。

我们先对离散化后的点排个序,然后考虑两个 \(x\) 相同的点 \(x,y1\) 和 \(x,y2\) 之间的所有点的方案数。

显然是:

\[C_{y1\_UP}^{k}\times C_{y2\_DOWN}^{k}\times \sum_{y1<l<y2}C_{l\_LEFT}^{k}\times C_{l\_RIGHT}^{k}
\]

你们意会一下。

观察这个式子,\(C_{y1\_UP}^{k}\times C_{y2\_DOWN}^{k}\) 当前已知,可以用前缀和维护 \(\sum C_{l\_LEFT}^{k}\times C_{l\_RIGHT}^{k}\)。

那么我们就开一个树状数组,维护前 \(i\) 行的 \(C_{l\_LEFT}^{k}\times C_{l\_RIGHT}^{k}\) 之和,每次碰到一个点 \(x,yy\) 时把当前行的影响清除,再令 \(yy\_LEFT+1,yy\_RIGHT-1\),再重新计入前缀和。

可以参考代码中 Solve 函数中变量 \(u\) 的求法。

时间复杂度 \(O(nlogn)\)。

我这个菜鸡居然因为取模取错了调了两节课。

Code

  1. #include <bits/stdc++.h>
  2. #define _for(i,a,b) for(ll i=a;i<=b;++i)
  3. #define for_(i,a,b) for(ll i=a;i>=b;--i)
  4. #define ll long long
  5. using namespace std;
  6. const ll N=1e5+10,P=2147483648;
  7. ll n,m,w,k,q[N],h[N],z[N],y[N],ans;
  8. struct tree{ll x,y;}t[N];
  9. inline ll rnt(){
  10. ll x=0,w=1;char c=getchar();
  11. while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
  12. while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
  13. return x*w;
  14. }
  15. namespace SZSZ{
  16. /*树状数组*/
  17. ll b[N];
  18. inline ll lowbit(ll x){return x&-x;}
  19. inline void UpDate(ll x,ll y){
  20. while(x<=w){
  21. b[x]=(b[x]+y)%P;
  22. x+=lowbit(x);
  23. }
  24. return;
  25. }
  26. inline ll Query(ll x){
  27. if(x==0)return 0;
  28. ll sum=0;
  29. while(x){
  30. sum=(sum+b[x])%P;
  31. x-=lowbit(x);
  32. }
  33. return sum;
  34. }
  35. }
  36. namespace LISAN{
  37. /*离散化*/
  38. vector<ll>xx,yy;
  39. inline bool cmp(tree a,tree b){
  40. if(a.x==b.x)return a.y<b.y;
  41. return a.x<b.x;
  42. }
  43. inline void Add(ll x,ll y){
  44. xx.push_back(x);
  45. yy.push_back(y);
  46. return;
  47. }
  48. inline void LiSan(){
  49. sort(xx.begin(),xx.end());
  50. sort(yy.begin(),yy.end());
  51. xx.erase(unique(xx.begin(),xx.end()),xx.end());
  52. yy.erase(unique(yy.begin(),yy.end()),yy.end());
  53. _for(i,1,w){
  54. t[i].x=lower_bound(xx.begin(),xx.end(),t[i].x)-xx.begin()+1;
  55. t[i].y=lower_bound(yy.begin(),yy.end(),t[i].y)-yy.begin()+1;
  56. ++h[t[i].x],++y[t[i].y];
  57. }
  58. sort(t+1,t+w+1,cmp);
  59. return;
  60. }
  61. }
  62. namespace SOLVE{
  63. ll c[N*20][20]={0};
  64. /*预处理组合数*/
  65. inline void PreC(){
  66. c[0][0]=1;
  67. _for(i,1,w){
  68. c[i][0]=1;
  69. _for(j,1,min(k,i))
  70. c[i][j]=(c[i-1][j]+c[i-1][j-1])%P;
  71. }
  72. }
  73. /*求解*/
  74. inline ll Solve(){
  75. PreC();
  76. _for(i,1,w-1){
  77. ++q[t[i].x];
  78. ++z[t[i].y];
  79. if(t[i].x==t[i+1].x&&q[t[i].x]>=k&&h[t[i].x]-q[t[i].x]>=k){
  80. ll up=c[q[t[i].x]][k];
  81. ll dn=c[h[t[i].x]-q[t[i].x]][k];
  82. ll ri=SZSZ::Query(t[i+1].y-1)-SZSZ::Query(t[i].y);
  83. ans+=((up*dn+P)%P*ri+P)%P;
  84. ans%=P;
  85. }
  86. ll u=((c[z[t[i].y]][k]*c[y[t[i].y]-z[t[i].y]][k]+P)%P-(SZSZ::Query(t[i].y)-SZSZ::Query(t[i].y-1)+P)%P+P)%P;
  87. SZSZ::UpDate(t[i].y,u);
  88. }
  89. return ans;
  90. }
  91. }
  92. int main(){
  93. n=rnt(),m=rnt(),w=rnt();
  94. _for(i,1,w){
  95. t[i].x=rnt(),t[i].y=rnt();
  96. LISAN::Add(t[i].x,t[i].y);
  97. }
  98. k=rnt();
  99. LISAN::LiSan();
  100. printf("%lld\n",SOLVE::Solve());
  101. return 0;
  102. }
  103. /*
  104. */

「题解报告」P2154 虔诚的墓主人的更多相关文章

  1. 「题解报告」 P3167 [CQOI2014]通配符匹配

    「题解报告」 P3167 [CQOI2014]通配符匹配 思路 *和?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配. 我们首先把原字符串分成多个以一个通 ...

  2. 「题解报告」P4577 [FJOI2018]领导集团问题

    题解 P4577 [FJOI2018]领导集团问题 题解区好像没有线段树上又套了二分的做法,于是就有了这片题解. 题目传送门 怀着必 WA 的决心交了两发,一不小心就过了. 题意 求一个树上最长不下降 ...

  3. 「题解报告」SP16185 Mining your own business

    题解 SP16185 Mining your own business 原题传送门 题意 给你一个无向图,求至少安装多少个太平井,才能使不管那个点封闭,其他点都可以与有太平井的点联通. 题解 其他题解 ...

  4. 「题解报告」Blocks

    P3503 Blocks 题解 原题传送门 思路 首先我们可以发现,若 \(a_l\) ~ \(a_r\) 的平均值大于等于 \(k\) ,则这个区间一定可以转化为都大于等于 \(k\) 的.我们就把 ...

  5. 「题解报告」P3354

    P3354 题解 题目传送门 一道很恶心的树形dp 但是我喜欢 题目大意: 一片海旁边有一条树状的河,入海口有一个大伐木场,每条河的分叉处都有村庄.建了伐木场的村庄可以直接处理木料,否则要往下游的伐木 ...

  6. 「题解报告」CF1067A Array Without Local Maximums

    大佬们的题解都太深奥了,直接把转移方程放出来让其他大佬们感性理解,蒟蒻们很难理解,所以我就写了一篇让像我一样的蒟蒻能看懂的题解 原题传送门 动态规划三部曲:确定状态,转移方程,初始状态和答案. --神 ...

  7. 「题解报告」P7301 【[USACO21JAN] Spaced Out S】

    原题传送门 神奇的5分算法:直接输出样例. 20分算法 直接把每个点是否有牛的状态DFS一遍同时判断是否合法,时间复杂度约为\(O(2^{n^2})\)(因为有判断合法的剪枝所以会比这个低).而在前四 ...

  8. 【Luogu】P2154虔诚的墓主人(树状数组)

    题目链接 这题就是考虑我们有这样一个情况

  9. bzoj1227 P2154 [SDOI2009]虔诚的墓主人

    P2154 [SDOI2009]虔诚的墓主人 组合数学+离散化+树状数组 先看题,结合样例分析,易得每个墓地的虔诚度=C(正左几棵,k)*C(正右几棵,k)*C(正上几棵,k)*C(正下几棵,k),如 ...

随机推荐

  1. 【Srping】事务的执行原理(一)

    在使用事务的时候需要添加@EnableTransactionManagement注解来开启事务,那么就从@EnableTransactionManagement入手查看一下事务的执行原理. @Enab ...

  2. SpringBoot + JWT + Redis 开源知识社区系统

    「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识.准备 Java 面试,首选 JavaGuide!:https://javaguide.cn/ 你好,我是 Guide!这 ...

  3. SAP Column tree

    code as bellow *&---------------------------------------------------------------------* *& I ...

  4. UiPath存在图像Image Exists的介绍和使用

    一.Image Exists的介绍 检查是否在指定的UI元素中找到图像,输出的是一个布尔值 二.Image Exists在UiPath中的使用 1. 打开设计器,在设计库中新建一个Sequence,为 ...

  5. Linux用户、组 管理

    Linux安全模型 3A: Authentication:认证,验证用户身份 Authorization:授权,不同的用户设置不同权限 Accouting|Audition:审计 Linux用户: 管 ...

  6. NC17059 队列Q

    NC17059 队列Q 题目 题目描述 ZZT 创造了一个队列 Q.这个队列包含了 N 个元素,队列中的第 i 个元素用 \(Q_i\) 表示.Q1 表示队头元素,\(Q_N\) 表示队尾元素.队列中 ...

  7. k8s之有状态服务部署基石(基础知识)

    PV&PVC&HeadlessService 4.1.什么是无状态/有状态服务? 无状态服务: 1.没有实时的数据需要存储 (即使有,也是静态数据) 2.服务集群网络中,拿掉一个服务后 ...

  8. 跨平台(32bit和64bit)的 printf 格式符 %lld 输出64位的解决方式

    问题描述 在 C/C++ 开发中,使用 printf 打印 64 位变量比较常用,通常在 32 位系统中使用 %lld 输出 64 位的变量,而在 64 位系统中则使用 %ld: 如果在 32 位系统 ...

  9. 【C++】学生管理系统

    [C++]学生管理系统 一道非常经典的C语言题目,用C++实现   题目如下: 输入功能:由键盘输入10个学生的学号.姓名.三科成绩,并计算出平均成绩和总成绩,然后将它存入文件stud.dat. 插入 ...

  10. java中AOP的环绕通知

    pom.xml <dependencies> <dependency> <groupId>org.springframework</groupId> & ...