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 的个数这一步骤(这个步骤其实就是求卷积啊),完 ...
随机推荐
- jquery.validation.js 表单验证
jquery.validation.js 表单验证 官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation jQuer ...
- Eclipse主题更改
1. 直接安装color theme eclipse:Help->Install New Software->Work with:Update Site -http://eclipse-c ...
- backtracking(回溯算法)
http://blog.csdn.net/zxasqwedc/article/details/42270215 permutation的程式码都会长成这样的格式: ] = { 'a', 'b', 'c ...
- 复制Informational constraints on LUW DB2 v105
An informational constraint is a constraint attribute that can be used by the SQL compiler to improv ...
- [转]c++ vector 遍历方式
挺有趣的,转来记录 随着C++11标准的出现,C++标准添加了许多有用的特性,C++代码的写法也有比较多的变化. vector是经常要使用到的std组件,对于vector的遍历,本文罗列了若干种写 ...
- 1.Windows安装PostgreSQL
按照下面的步骤,Windows机器上安装PostgreSQL.请确保已开启第三方防病毒,同时安装. 挑选你想要的PostgreSQL的版本号,可以点击以下链接下载 EnterpriseDB Windo ...
- Android源码-学习随笔
在线代码网站1:http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android/ 书籍: ...
- vim、gvim加载文件慢
1. strace -f -T -o vim.strace vim 2. vim --startuptime "vim-time.txt" 3. gvim -f
- .net学习之Attribute特性和EF关键知识点
一.Attribute特性/标签1.Attribute用来对类.属性.方法等标注额外的信息,贴一个标签简单的说,定制特性Attribute,本质上就是一个类,它为目标元素提供关联附加信息,并在运行时以 ...
- IE文档版本和文档流模式
使用X-UA-Compatible来设置IE浏览器兼容模式 文件兼容性用于定义让IE如何编译你的网页.此文件解释文件兼容性,如何指定你网站的文件兼容性模式以及如何判断一个网页该使用的文件模式. < ...