题目大意就是给你一个R*C的棋盘,上面有超级兵,这种超级兵会攻击 同一行、同一列、同一主对角线的所有元素,现在给你N个超级兵的坐标,需要你求出有多少方块是不能被攻击到的(R,C,N<50000)

遇到这种计数问题就要联想到容斥(组合数学太重要了),由容斥原理:

被攻击的方块数=行被攻击的方块数+列被攻击的方块数+主对角线被攻击的方块数-同时被行、列攻击的方块数-同时被行、对角线攻击的方块数-同时被列、对角线攻击的方块数+同时被行、列、对角线攻击的方块数

因为行列都不会很大,所以我们用三个数组分别记录行、列、对角线上含有超级兵的情况(从1开始)。对于对角线,我们不妨从右上角开始编起,从1-R+C-1,那么对于任意一块<x,y>,它所属的对角线为x-y+C

开始计数:

行被攻击的方块数和列被攻击的方块数,这个很简单,就是扫一遍数组,然后如果有超级兵就加上

主对角线被攻击的方块数:我们需要知道对于任何一条主对角线,在R*C的棋盘里,它的主对角线有多长,根据推导,我们发现当对角线编号为1~C的时候,对角线都是从第一行开始的,它的长度按道理来讲应该是随着编号的增加递增的,但是当长度达到一定的时候就会收到行数的限制,因此长度为min(i,R)。可以理解为,i就是因为收到列数的限制的最大的长度,但是同时还需要收到行数的限制。当编号为C+1~R+C-1的时候,此时长度总体来讲会递减,主要收到行数的限制,但是同样也会收到列数的限制,因此长度为min(R+C-i,C)。得到长度以后我们就可以遍历一遍得到主对角线被攻击的方块数

同时被行、列攻击的方块数:这个很简单,就是总共被攻击的行数*被攻击的列数

同时被行、对角线攻击的方块数:我们只要知道对角线在行上的范围,然后再统计在这个范围内有多少行被攻击就可以了。为了快速得到一个范围内有多少行被攻击,我们可以用一个前缀数组,来计算某一个行区间内有多少被攻击。现在重点在于如何求对角线所占行的范围。同样的我们需要进行分类讨论:当序号为1~C的时候,每一个对角线都是从第1行开始的,我们只需要加上上面求得的长度就能够得到最后一行应该为min(i,C)。当序号为C+1~R+C-1的时候,每一行是从i-C+1开始的,到i-C+1+min(R+C-i,C)结束。

同时被列、对角线攻击的方块数:分析同上,我们这里只讨论每一条对角线列的范围额:当序号为1~C的时候,是C-i+1C-i+1+min(i,C),当序号为C+1~R+C-1的时候,是1min(R+C-1,C)

同时被行、列、对角线攻击的方块数:这个可能就没有很简单了,我们需要求出所有既被行、列攻击,又被对角线攻击的块数。设XY列,则如果要同时被攻击,应该还存在一个对角线X-Y+C,观察这个式子,我们有什么方法迅速得到吗?好多个数相加、好多个数相减,我们还需要得到所有的结果,而且还不能遍历(会超时),我们就应该联想到FFT,加减运算转化为多项式乘法运算后,使用FFT就能nlogn解决问题。那么这两个多项式应该怎么构造呢?行多项式我们不妨就设为r[i]*xi,那么列多项式应该为c[i]*xC-i,这样运算以后的结果就是xi-j+C,得到的对角线的系数就是这条对角线同时被行列攻击的块数(因为i,j是不同的,所以是这个对角线上的不同的块)。如果i-j+C处恰好有一条对角线,接说明这些块需要加上。

可以看一哈我写的代码,应该还是比较清晰的。

AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<cmath>using namespace std;
const int MAXN=1<<17;
const double PI=acos(-1.0);
typedef long long ll;int read()
{int x=0,sign=1; char c=getchar();while(c<'0' || c>'0') {if(c=='-') sign=-1; c=getchar();}while(c>='0' && c<='9'){x=x*10+c-'0'; c=getchar();}return x*sign;
}struct complex
{double r,i;complex(double _r=0,double _i=0):r(_r),i(_i){}complex operator +(const complex &b) {return complex(r+b.r,i+b.i);}complex operator -(const complex &b) {return complex(r-b.r,i-b.i);}complex operator *(const complex &b) {return complex(r*b.r-i*b.i,r*b.i+i*b.r);}
}A[MAXN],B[MAXN];void change(complex y[],int len)
{int i,j,k;for(i = 1, j = len/2;i < len-1;i++){if(i < j)swap(y[i],y[j]);k = len/2;while( j >= k){j -= k;k /= 2;}if(j < k)j += k;}
}void fft(complex y[],int len,int on)
{change(y,len);for(int h = 2;h <= len;h <<= 1){complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));for(int j = 0;j < len;j += h){complex w(1,0);for(int k = j;k < j+h/2;k++){complex u = y[k];complex t = w*y[k+h/2];y[k] = u+t;y[k+h/2] = u-t;w = w*wn;}}}if(on == -1)for(int i = 0;i < len;i++)y[i].r /= len;
}void FFT(int a[],int la,int b[],int lb)//la,lb分别是a,b数组的最高位+1
{int len=1; while(len<la+lb) len<<=1;for(int i=0;i<la;++i) A[i]=complex(a[i],0);for(int i=la;i<len;++i) A[i]=complex(0,0);for(int i=0;i<lb;++i) B[i]=complex(b[i],0);for(int i=lb;i<len;++i) B[i]=complex(0,0);fft(A,len,1); fft(B,len,1);for(int i=0;i<len;++i) A[i]=A[i]*B[i];fft(A,len,-1);
}int R,C,D,N;
int r[MAXN],c[MAXN],d[MAXN];
int sumr[MAXN],sumc[MAXN];//行列前缀和
ll ans;int main()
{//freopen("data.txt","w",stdout);int T;//T=read();scanf("%d",&T);for(int Case=1;Case<=T;++Case){//initans=0; sumr[0]=sumc[0]=0;for(int i=0;i<=R;i++) r[i]=0;for(int i=0;i<=C;i++) c[i]=0;for(int i=0;i<=D;i++) d[i]=0;//read //R=read(); C=read(); N=read();scanf("%d%d%d",&R,&C,&N);int u,v;while(N--){//u=read(); v=read();scanf("%d%d",&u,&v);r[u]=1; c[v]=1; d[u-v+C]=1;}//统计行列被攻击的块数,得到前缀和 for(int i=1;i<=R;++i){if(r[i]) ans+=C; sumr[i]=sumr[i-1]+r[i];}for(int i=1;i<=C;++i){if(c[i]) ans+=R; sumc[i]=sumc[i-1]+c[i];}//test//减去行列同时被攻击的块数ans-=sumr[R]*sumc[C]; //统计主对角线被攻击的块数//减去同时被行和对角线、列和对角线攻击的块数 //1~R-1+C  X-Y+CD=R-1+C;for(int i=1;i<=D;++i){if(d[i]){if(i<=C)//对角线块数递增,行数限制 {int dr1=0,dr2=min(i,R);  //行数始末 int dc1=C-i,dc2=dc1+dr2;//列数始末 ans+=dr2;ans-=sumr[dr2]-sumr[dr1];ans-=sumc[dc2]-sumc[dc1];}else//对角线块数递减,列数限制 {int dc1=0,dc2=min(R+C-i,C);//列数始末 int dr1=i-C,dr2=dr1+dc2;    //行数始末ans+=min(R+C-i,C);ans-=sumr[dr2]-sumr[dr1];ans-=sumc[dc2]-sumc[dc1];}}}//加上同时被行列对角线攻击的方块reverse(c,c+C+1);FFT(r,R+1,c,C+1);for(int i=1;i<=D;++i){if(d[i]){ans+=(ll)(A[i].r+0.5);    }}printf("Case %d: %lld\n",Case,(ll)R*C-ans);//if(Case!=T) printf("\n");}return 0;
}

UVa12633-Super Rooks on Chessboard-容斥+FFT相关推荐

  1. UVA12633 Super Rooks on Chessboard

    题目描述 题解: 第一眼满眼骚操作,然后全部否掉. 然后屈服于题解,才发现这题这么执掌. 首先,如果这个东西是普通的车,那我们可以记录一下$x,y$的覆盖情况,然后减一下; 但是这个可以斜着走. 所以 ...

  2. UOJ#449. 【集训队作业2018】喂鸽子 min-max容斥,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ449.html 题解 设 f(i) 表示给 i 只鸽子喂食使得至少一只鸽子被喂饱的期望次数,先 min-max容斥 一下. ...

  3. Codeforces 1342E Placing Rooks(容斥+组合数学)

    题目链接:E. Placing Rooks 题意:给定一个N*棋盘,要求摆放n个rooks(国际象棋里能横竖走的那啥),使得每个格子都能被rooks攻击到,并且正好有k对rooks能相互攻击到,求有多 ...

  4. 【集训队作业2018】青春猪头少年不会梦到兔女郎学姐(容斥)(分治FFT)

    简要题意: 给定 nnn 种颜色的球,第 iii 种颜色的球数量为 aia_iai​ 个,一种排列的贡献可以如下计算:先把这个序列首尾相连,然后把所有相邻且颜色相同的段拿出来,贡献为他们的长度之积,求 ...

  5. 【LOJ#575】【LNR#2】不等关系(容斥,动态规划,分治FFT)

    [LOJ#575][LNR#2]不等关系(容斥,动态规划,分治FFT) 题面 LOJ 题解 一个暴力\(dp\),设\(f[i][j]\)表示考虑完了前\(i\)个位置,其中最后一个数在前面所有数中排 ...

  6. Leetcode 552.学生出勤记录‖ 动态规划+容斥

    题目链接:传送门 可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤.迟到.到场).记录中只含下面三种字符: 'A':Absent,缺勤 'L':Late,迟到 'P':P ...

  7. 容斥 + 树形dp ---- 2021 icpc 沈阳 L Perfect Matchings

    题目链接 题目大意: 就是给你一个2n2n2n个点的完全图,从这个图里面抽出2n−12n-12n−1条边,这些边形成一颗树,现在问你剩下的图里面点进行完美匹配有多少种方案? 解题思路: 一开始被完美匹 ...

  8. Luogu P4336 [SHOI2016]黑暗前的幻想乡(容斥,矩阵树定理,子集反演)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Luogu P4336 [SHOI2016]黑暗前的幻想乡(容斥,矩阵树定理) Problem n≤1 ...

  9. P3175 [HAOI2015]按位或(Min - Max容斥,FMT,概率期望,全网最清晰的题解!)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/P3175 Prob ...

最新文章

  1. 在CentOS上搭建PHP服务器环境
  2. Android的Crash崩溃解决方案-Bugly的使用
  3. clojure学习记录
  4. 页面调用系统window打印
  5. [react] 有用过react的Fragment吗?它的运用场景是什么
  6. mysql分组获取其他字段_sqlserver group by后获取其他字段(多种方法)
  7. 李开复离职后谷歌将在中国消亡
  8. C#写一个URL编码转换GB23121的方法,然后可以取到天气预报
  9. Windows Internet Explorer 8 for Windows Vista 和 Windows Server 2008
  10. [转]怎么查看端口占用情况?
  11. Boxfilter 块滤波器
  12. 如何使用计算机蓝牙设备管理器,电脑蓝牙bluetooth怎么使用_win7蓝牙bluetooth使用教程-系统城...
  13. android6.0 Activity(四) Surface创建
  14. 国微高校 html源码,国微CMS模板结构_模板教程_广州国微软件高校站群系统---领先的高校站群系统方案|全媒体方案|学校网站系统...
  15. 译OpenCms-10.5.3—— 1. 背景话题【Background topics】
  16. 以太网没有有效的IP配置
  17. linux opessl下载_linux Download openssl-1.0.2下载 openssl安装步骤
  18. 40079 钉钉_钉钉获取免登陆授权码CODE,返回:不存在的临时授权码40078
  19. 简单聊一聊如今火爆当下的数字孪生技术到底为何物
  20. ThreadLocal 是什么?有哪些使用场景?

热门文章

  1. 配置Ubuntu虚拟环境
  2. 智能小车37:异常在ARM、JAVA、硬件里的实现
  3. SCREEN屏幕编程时候必须保证SCREN中词典的字段格式必须和数据表中字段的类型长度一致!...
  4. Jmeter参数化 CSV Data Set Config界面说明
  5. 关于eclipse的indigo版中文注释时字体太小的问题(转)
  6. Android中的Handler机制
  7. .net 笔记尝试(二)
  8. matlab批量修改txt内容_MATLAB作图实例:18:为饼图添加文本标签和百分比
  9. 链表排序c++代码_[链表面试算法](一) 链表的删除-相关题型总结(6题)
  10. 视网膜脱离oct报告图_刚刚,爱尔眼科发布关于艾芬医生诊疗过程的核查报告