UVa12633 Super Rooks on Chessboard(容斥 + FFT)
题目
Source
http://acm.hust.edu.cn/vjudge/problem/42145
Description
Let’s assume there is a new chess piece named Super-rook. When placed at a cell of a chessboard, it attacks all the cells that belong to the same row or same column. Additionally it attacks all the
cells of the diagonal that goes from top-left to bottom-right direction through that cell.
N Super-rooks are placed on a R × C chessboard. The rows are numbered 1 to R from top to bottom and columns are numbered 1 to C from left to right of the chessboard. You have to find the number of cells of the chessboard which are not attacked by any of the Super-rooks.
The picture on the left shows the attacked cells when a Super-rook is placed at cell (5, 3) of a 6 × 6 chessboard. And the picture on the right shows the attacked cells when three Super-rooks are placed at cells (3, 4), (5, 3) and (5, 6). These pictures (Left and right one) corresponds to the first and second sample input respectively.
Input
First line of input contains an integer T (1 ≤ T ≤ 20) which is the number of test cases. The first line of each test case contains three integers R, C and N (1 ≤ R, C, N ≤ 50, 000). The next N lines contain two integers r, c giving the row and column of a Super-rook on the chessboard (1 ≤ r ≤ R and 1 ≤ c ≤ C). You may assume that two Super-rooks won’t be placed on the same cell.
Output
For each test case, output the case number followed by the number of cells which are not attacked by any of the Super-rook.
Sample Input
2
6 6 1
5 3
6 6 3
3 4
5 3
5 6
Sample Output
Case 1: 22
Case 2: 9
分析
题目大概说一个R*C的棋盘上有N个超级车棋子,这种棋子可以往水平、竖直和主对角线方向移动任意格,问棋盘没有被这些超级车攻击的格子有多少个。
这题解法从叉姐的一个讲义中看到的,自己想了下,实现了下就AC了。
解法就是利用容斥去求得有多少个格子被攻击:
- 被攻击的行格子数 + 被攻击的列格子数 + 被攻击的主对角线格子数 - 行列交叉格子数 - 行对角交叉格子数 + 行列主对角交叉格子数
一开始不妨给行、列、对角编好号。行列从0开始上到下、左到右这样;而对于主对角线,可以知道主对角线上每一格的的行坐标-列坐标都是定值,所以可以从右上到左下从0到R+C-1给每条对角线编号,而对于任意一格(x,y)其所属对角线编号就等于x-y+C-1。
然后上面那个式子前面5个求没什么问题,就是比较复杂。。关键是最后一个,相当于求。。直接截图吧不会表达。。

代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 133333
const double PI=acos(-1.0); struct Complex{
double real,imag;
Complex(long double _real,long double _imag):real(_real),imag(_imag){}
Complex(){}
Complex operator+(const Complex &cp) const{
return Complex(real+cp.real,imag+cp.imag);
}
Complex operator-(const Complex &cp) const{
return Complex(real-cp.real,imag-cp.imag);
}
Complex operator*(const Complex &cp) const{
return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
}
void setValue(long double _real=0,long double _imag=0){
real=_real; imag=_imag;
}
}; int len;
Complex wn[MAXN],wn_anti[MAXN]; void FFT(Complex y[],int op){
for(int i=1,j=len>>1,k; i<len-1; ++i){
if(i<j) swap(y[i],y[j]);
k=len>>1;
while(j>=k){
j-=k;
k>>=1;
}
if(j<k) j+=k;
}
for(int h=2; h<=len; h<<=1){
Complex Wn=(op==1?wn[h]:wn_anti[h]);
for(int i=0; i<len; i+=h){
Complex W(1,0);
for(int j=i; j<i+(h>>1); ++j){
Complex u=y[j],t=W*y[j+(h>>1)];
y[j]=u+t;
y[j+(h>>1)]=u-t;
W=W*Wn;
}
}
}
if(op==-1){
for(int i=0; i<len; ++i) y[i].real/=len;
}
}
void Convolution(Complex A[],Complex B[],int n){
for(len=1; len<(n<<1); len<<=1);
for(int i=n; i<len; ++i){
A[i].setValue();
B[i].setValue();
} FFT(A,1); FFT(B,1);
for(int i=0; i<len; ++i){
A[i]=A[i]*B[i];
}
FFT(A,-1);
} int x[55555],y[55555];
Complex A[MAXN],B[MAXN];
long long R[55555],C[55555],D[55555*2]; long long get_sum(long long *x,int l,int r){
if(l==0) return x[r];
return x[r]-x[l-1];
} int main(){
for(int i=0; i<MAXN; ++i){
wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
wn_anti[i].setValue(wn[i].real,-wn[i].imag);
}
int t,r,c,n;
scanf("%d",&t);
for(int cse=1; cse<=t; ++cse){
scanf("%d%d%d",&r,&c,&n);
memset(R,0,sizeof(R));
memset(C,0,sizeof(C));
memset(D,0,sizeof(D));
for(int i=0; i<n; ++i){
scanf("%d%d",x+i,y+i);
--x[i]; --y[i];
R[x[i]]=1; C[y[i]]=1; D[x[i]-y[i]+c-1]=1;
}
long long ans=0;
for(int i=0; i<r; ++i){
if(R[i]) ans+=c;
}
for(int i=0; i<c; ++i){
if(C[i]) ans+=r;
} for(int i=0; i<r+c-1; ++i){
if(D[i]==0) continue;
if(i<c) ans+=min(r,i+1);
else ans+=min(r-i+c-1,c);
}
for(int i=1; i<r; ++i) R[i]+=R[i-1];
for(int i=1; i<c; ++i) C[i]+=C[i-1];
ans-=R[r-1]*C[c-1];
for(int i=0; i<r+c-1; ++i){
if(D[i]==0) continue;
if(i<c){
int x=0,y=c-i-1;
int k=min(r-x,c-y);
ans-=get_sum(R,x,x+k-1);
ans-=get_sum(C,y,y+k-1);
}else{
int x=i-c+1,y=0;
int k=min(r-x,c-y);
ans-=get_sum(R,x,x+k-1);
ans-=get_sum(C,y,y+k-1);
}
} for(int i=0; i<r; ++i){
A[i].setValue(get_sum(R,i,i));
}
for(int i=0; i<c; ++i){
B[c-i-1].setValue(get_sum(C,i,i));
}
for(int i=r; i<c; ++i){
A[i].setValue();
}
for(int i=c; i<r; ++i){
B[i].setValue();
}
Convolution(A,B,max(r,c));
for(int i=0; i<r+c-1; ++i){
if(D[i]==0) continue;
ans+=(long long)(A[i].real+0.5);
} printf("Case %d: %lld\n",cse,(long long)r*c-ans);
}
return 0;
}
UVa12633 Super Rooks on Chessboard(容斥 + FFT)的更多相关文章
- UVA12633 Super Rooks on Chessboard
题目描述 题解: 第一眼满眼骚操作,然后全部否掉. 然后屈服于题解,才发现这题这么执掌. 首先,如果这个东西是普通的车,那我们可以记录一下$x,y$的覆盖情况,然后减一下; 但是这个可以斜着走. 所以 ...
- UVA 12633 Super Rooks on Chessboard [fft 生成函数]
Super Rooks on Chessboard UVA - 12633 题意: 超级车可以攻击行.列.主对角线3 个方向. R * C 的棋盘上有N 个超级车,问不被攻击的格子总数. 行列好好做啊 ...
- UOJ#449. 【集训队作业2018】喂鸽子 min-max容斥,FFT
原文链接www.cnblogs.com/zhouzhendong/p/UOJ449.html 题解 设 f(i) 表示给 i 只鸽子喂食使得至少一只鸽子被喂饱的期望次数,先 min-max容斥 一下. ...
- UVA 12633 Super Rooks on Chessboard(FFT)
题意: 给你一个R*C的棋盘,棋盘上的棋子会攻击,一个棋子会覆盖它所在的行,它所在的列,和它所在的从左上到右下的对角线,那么问这个棋盘上没有被覆盖的棋盘格子数.数据范围R,C,N<=50000 ...
- UVA 12633 Super Rooks on Chessboard ——FFT
发现对角线上的和是一个定值. 然后就不考虑斜着,可以处理出那些行和列是可以放置的. 然后FFT,统计出每一个可行的项的系数和就可以了. #include <map> #include &l ...
- [UVA 12633] Super Rooks on Chessboard FFT+计数
如果只有行和列的覆盖,那么可以直接做,但现在有左上到右下的覆盖. 考虑对行和列的覆盖情况做一个卷积,然后就有了x+y的非覆盖格子数. 然后用骑士的左上到右下的覆盖特判掉那些x+y的格子就可以了. 注意 ...
- UVA 12633 Super Rooks on Chessboard (生成函数+FFT)
题面传送门 题目大意:给你一张网格,上面有很多骑士,每个骑士能横着竖着斜着攻击一条直线上的格子,求没被攻击的格子的数量总和 好神奇的卷积 假设骑士不能斜着攻击 那么答案就是没被攻击的 行数*列数 接下 ...
- [BZOJ5306][HAOI2018]染色(容斥+FFT)
https://www.cnblogs.com/zhoushuyu/p/9138251.html 注意如果一开始F(i)中内层式子中j枚举的是除前i种颜色之外还有几种出现S次的颜色,那么后面式子就会难 ...
- HDU 4609 3-idiots FFT+容斥
一点吐槽:我看网上很多分析,都是在分析这个题的时候,讲了半天的FFT,其实我感觉更多的把FFT当工具用就好了 分析:这个题如果数据小,统计两个相加为 x 的个数这一步骤(这个步骤其实就是求卷积啊),完 ...
随机推荐
- checkbox复选框全选
HTML: <input type="checkbox" class="all"> <input type="checkbox&qu ...
- Xcode开发中的6个小技巧
Xcode是iPhone和iPad开发者用来编码或者开发iOS app的IDE.Xcode有很多小巧但很有用的功能,很多时候我们可能没有注意到它们,也或者我们没有在合适的水平使用这些功能简化我们的iO ...
- 对于spark以及hadoop的几个疑问(转)
Hadoop是啥?spark是啥? spark能完全取代Hadoop吗? Hadoop和Spark属于哪种计算计算模型(实时计算.离线计算)? 学习Hadoop和spark,哪门语言好? 哪里能找到比 ...
- JavaScript基础——使用数组
Array对象提供存储和处理一组其他对象的一种手段.数组可以存储数值.字符串或其他JavaScript对象.创建JavaScript数组有几种不同的方法.例如,下面的语句穿件同样的驻足的3个相同的版本 ...
- JQ JSON数据类型
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- [插件]jQuery multiselect初始化及默认值修改
下载地址:http://pan.baidu.com/s/1dE2daSD 1.Jquery多选下拉列表插件jquery multiselect功能介绍及使用 http://www.jb51.net/a ...
- ASP.NET Web API 配置返回的json字段的格式以及Action返回HttpResponseMessage类型和IHttpActionResult类型
1. 对于返回的Json对象格式是以“帕斯卡”风格的(例如“FirstName”),然而我们的Api有很大的可能被带有Javascript的客户端消费,对于JS开发者来说可能更适合“驼峰”风格(例如” ...
- Android的两种事件处理机制
UI编程通常都会伴随事件处理,Android也不例外,它提供了两种方式的事件处理:基于回调的事件处理和基于监听器的事件处理. 对于基于监听器的事件处理而言,主要就是为Android界面组件绑定特定的事 ...
- 在ubuntu上搭建开发环境8---Ubuntu搭建Android开发环境
需要首先配置好JDK环境 参看:http://www.cnblogs.com/xumenger/p/4460055.html 安装Eclipse 在Android developer的官网上直接下载a ...
- WinDbg 命令三部曲:(一)WinDbg 命令手册
本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 系列博文 <WinDbg 命令三部曲:(一)WinDbg 命令手册> <WinDb ...