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 的个数这一步骤(这个步骤其实就是求卷积啊),完 ...
随机推荐
- supersr--KVO/KVC
KVO内部实现原理 1.KVO是基于runtime机制实现的. 2.当某个类的对象第一次被观察是,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的set方法.派生类 ...
- Java网络连接之HttpURLConnection 与 HttpClient
HttpClient使用详解:http://blog.csdn.net/wangpeng047/article/details/19624529 注:HttpURLConnection输出流用ou ...
- Ubuntu下调整swap分区的大小
转自:http://blog.chinaunix.net/uid-7573623-id-2048964.html 由于安装oracle 的时候,swap太小不能继续安装,于是想有什么方法在不不用安装o ...
- WCF分布式开发必备知识(2):.Net Remoting
.Net Remoting技术,我们可以将其看作是一种分布式处理方式.作为应用程序之间通信的一种机制,.Net Remoting与MSMQ消息队列不同,它不支持离线脱机消息,另外只适合.Net平台间程 ...
- SVN 升级后出现You need to upgrade the working copy first.
今天将svn更新后,出现 svn: The working copy at 'E:\591woospace\kst_fashion_alipay_v1.2.0\src\com\kstapp\wansh ...
- sqlplus使用(一)
一,sqlplus 环境变量 sqlplus的环境变量(来自SQL*Plus® User's Guide and Reference Release 11.2) Parameter or Variab ...
- .NET Framework 4 与 .NET Framework 4 Client Profile
今天碰到的一个问题和Client Profile相关的.问题是这样的:一个WPF工程,需要引用另外几个.NET的assembly, 在WPF工程中添加了对这几个assembly的引用,并在程序中可以添 ...
- 使用pl/sql監控PROCEDURE執行時間
創建表 CREATE TABLE PROCESS_TIMING_LOG ( PROCESS_NAME VARCHAR2(50 BYTE), EXECUTION_DATE D ...
- hdu 4045 2011北京赛区网络赛F 组合数+斯特林数 ***
插板法基础知识 斯特林数见百科 #include<iostream> #include<cmath> #include<cstdio> #include<cs ...
- 25条提高Visual Studio编码和调试效率的技巧
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:工欲善其事必先利其器.就算手中已经有了利器,如果能掌握一些使用工具的技巧,让利器更加顺 ...