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 的个数这一步骤(这个步骤其实就是求卷积啊),完 ...
随机推荐
- 【转】深入Windows内核——C++中的消息机制
上节讲了消息的相关概念,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果 图1.效果图 Win32 ...
- 项目配置laungchImage
- 无根树转有根树(dfs,tree)
#include <bits/stdc++.h> #include <iostream> #include <queue> #include <stdio.h ...
- 前端模板artTemplate,handlerbars的使用心得
写前端页面肯定离不开模板渲染,就近期项目中用的两个前端模板做一些使用总结,顺便复习一下,也方便后面温故. 1,artTemplate 优点: 1,一般web端用得较多,执行速度通常是 Mustache ...
- jquery学习笔记-----插件开发的编写总结
一.对jQuery对象的扩展 ;(function($){ $.fn.extend( { fun1:abc,fun2:1bc … } ) })(jQuery) 这里采用立即执行模式,即不用调用也能执 ...
- Python 与 C# lambda表达式比较
Python里到lambda表达式非常简约, lam =lambda a: a*2 --> lam(3) 6 在某些情况下确实挺好用到.但是相比C#到lambda表达式,还是不够强大(我不是在黑 ...
- Delphi中record和packed record的区别
转载:http://blog.csdn.net/rznice/article/details/6566978 第一种不带packed关键字的结构体表明编译器编译时要求进行字对齐. 而第二种带packe ...
- GoLang搞一个基本的HTTP服务
慢慢和python的对应一下看看. package main import ( "fmt" "net/http" "strings" &qu ...
- iOS和Android的app界面设计规范(转)
记录一下iOS和Andoird的界面设计规范,方便进行标准的产品设计,并与设计师顺畅沟通 iOS篇 界面尺寸 设备 分辨率 状态栏高度 导航栏高度 标签栏高度 iPhone6 plus 1242×22 ...
- 用C#基于WCF创建TCP的Service供Client端调用
本文将详细讲解用C#基于WCF创建TCP的Service供Client端调用的详细过程 1):首先创建一个Windows Service的工程 2):生成的代码工程结构如下所示 3):我们将Servi ...