UVa12633 Super Rooks on Chessboard(容斥 + FFT)

时间:2024-01-05 14:17:02

题目

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个求没什么问题,就是比较复杂。。关键是最后一个,相当于求。。直接截图吧不会表达。。

UVa12633  Super Rooks on Chessboard(容斥 + FFT)

代码

#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;
}