题意:


给你一个R*C的棋盘,棋盘上的棋子会攻击,一个棋子会覆盖它所在的行,它所在的列,和它所在的从左上到右下的对角线,那么问这个棋盘上没有被覆盖的棋盘格子数。数据范围R,C,N<=50000

思路:


直接做肯定会超时,所以需要一种\(nlogn\)的算法。我们一步一步来。

首先,我们肯定需要给被覆盖的行被覆盖的列做上标记,visx标记被覆盖的行,visy标记被覆盖的列,visd标记被覆盖的对角线

那么就是 visx[r]=1,visy[c]=1,visd[r-c+C]=1,给对角线这么标号避免了负的下标,即从右上角开始到左下角从1标到R-1+C,而且下面还会用到。

然后,如果我们不考虑被覆盖的对角线,那么没有被覆盖的格子数就是未被覆盖的行数\(*\)未被覆盖的列数,但是还有被覆盖的对角线。

下面,我们设为行的覆盖情况的集合为{r1,r2,r3,ri,rR}其中下标代表行号,值为1或0,代表是否被覆盖,1是没被覆盖,0是被覆盖,列也一样{c1,c2,c3,cj,cC},我们再设对角线的{d1,d2,d3,dk,dx+y-1}但这里的值是这个对角线未被覆盖的值,

然后我们看,一开始我们没有考虑对角线,现在我们就要把对角线覆盖的部分从行列未覆盖的部分减去,那么我们就要知道在未考虑对角线覆盖情况下每个对角线没有被覆盖的格子数,然后根据visd把未被行列覆盖但被对角线覆盖的格子数减去。

那么每个对角线,那么标号为k的对角线的未被覆盖格子数是什么

\[\sum\sum(r_i\times c_j)(i-j+C=k)=d_k$$。
那么我们就发现了,$ri\times cj$就相当于系数相乘,下标i-j+C就相当于指数相加,那么这时候就可以把它转化为多项式了,相当于两个多项式相乘,那么就要用到FFT了。
下面就是多项式系数赋值了。首先行的多项式就这么顺序赋值即可,又因为指数相加结果是i-j+C,那么行的指数就是i,列的指数就是拿j的系数做指数C-j的系数,这样相加就可以得到上面的求和公式的效果了。套FFT模板搞一下就行了,最后再结合visd去重即可。

```cpp
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <complex>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
const double pi=acos(-1.0);
# define eps 1e-8
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FDR(i,a,n) for(int i=a; i>=n; --i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
inline int Scan() {
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
inline void Out(int a) {
if(a<0) {putchar('-'); a=-a;}
if(a>=10) Out(a/10);
putchar(a%10+'0');
}
const int N=50005;
//Code begin....

typedef complex<double> cmx;
int a[N<<2], b[N<<2];
cmx x[N<<2], y[N<<2];
bool visr[N<<2], visc[N<<2], visd[N<<2];
struct Node{int x, y;}node[N];

void change(cmx x[], int len) {
int i, j, k;
for(i=1, j=len>>1; i<len-1; ++i) {
if(i<j) swap(x[i],x[j]);
k=len>>1;
while(j>=k) j-=k, k>>=1;
if(j<k) j+=k;
}
}
void fft(cmx x[], int len, int on) {
change(x,len);
for(int i=2; i<=len; i<<=1) {
cmx wn(cos(-on*2*pi/i),sin(-on*2*pi/i));
for(int j=0; j<len; j+=i) {
cmx w(1,0);
FOR(k,j,j+i/2-1) {
cmx u=x[k], v=x[k+i/2]*w;
x[k]=u+v; x[k+i/2]=u-v; w*=wn;
}
}
}
if(on==-1) FOR(i,0,len-1) x[i]/=len;
}
int main()
{
int T, r, c, R, C, n;
scanf("%d",&T);
FOR(cas,1,T) {
mem(visr,0); mem(visc,0); mem(visd,0); mem(a,0); mem(b,0); r=0; c=0;
LL ans=0;
scanf("%d%d%d",&R,&C,&n);
FOR(i,1,n) scanf("%d%d",&node[i].x,&node[i].y), visr[node[i].x]=visc[node[i].y]=visd[node[i].x-node[i].y+C]=true;
FOR(i,1,R) if (!visr[i]) a[i]=1, ++r;
FOR(i,1,C) if (!visc[i]) b[C-i]=1, ++c;
ans=(LL)r*c;
int len=1;
while (len<=R+C) len<<=1;
FOR(i,0,len-1) x[i]=cmx(a[i],0), y[i]=cmx(b[i],0);
fft(x,len,1); fft(y,len,1);
FOR(i,0,len-1) x[i]=x[i]*y[i];
fft(x,len,-1);
FOR(i,0,len-1) if (visd[i]) ans-=(int)(x[i].real()+0.5);
printf("Case %d: %lld\n",cas,ans);
}
return 0;
}

```\]

UVA 12633 Super Rooks on Chessboard(FFT)的更多相关文章

  1. UVA 12633 Super Rooks on Chessboard [fft 生成函数]

    Super Rooks on Chessboard UVA - 12633 题意: 超级车可以攻击行.列.主对角线3 个方向. R * C 的棋盘上有N 个超级车,问不被攻击的格子总数. 行列好好做啊 ...

  2. UVA 12633 Super Rooks on Chessboard ——FFT

    发现对角线上的和是一个定值. 然后就不考虑斜着,可以处理出那些行和列是可以放置的. 然后FFT,统计出每一个可行的项的系数和就可以了. #include <map> #include &l ...

  3. [UVA 12633] Super Rooks on Chessboard FFT+计数

    如果只有行和列的覆盖,那么可以直接做,但现在有左上到右下的覆盖. 考虑对行和列的覆盖情况做一个卷积,然后就有了x+y的非覆盖格子数. 然后用骑士的左上到右下的覆盖特判掉那些x+y的格子就可以了. 注意 ...

  4. UVA 12633 Super Rooks on Chessboard (生成函数+FFT)

    题面传送门 题目大意:给你一张网格,上面有很多骑士,每个骑士能横着竖着斜着攻击一条直线上的格子,求没被攻击的格子的数量总和 好神奇的卷积 假设骑士不能斜着攻击 那么答案就是没被攻击的 行数*列数 接下 ...

  5. UVa12633 Super Rooks on Chessboard(容斥 + FFT)

    题目 Source http://acm.hust.edu.cn/vjudge/problem/42145 Description Let’s assume there is a new chess ...

  6. UVA12633 Super Rooks on Chessboard

    题目描述 题解: 第一眼满眼骚操作,然后全部否掉. 然后屈服于题解,才发现这题这么执掌. 首先,如果这个东西是普通的车,那我们可以记录一下$x,y$的覆盖情况,然后减一下; 但是这个可以斜着走. 所以 ...

  7. UVA - 12298 Super Poker II NTT

    UVA - 12298 Super Poker II NTT 链接 Vjudge 思路 暴力开个桶,然后统计,不过会T,用ntt或者fft,ntt用个大模数就行了,百度搜索"NTT大模数&q ...

  8. UVA - 11134 Fabled Rooks[贪心 问题分解]

    UVA - 11134 Fabled Rooks We would like to place n rooks, 1 ≤ n ≤ 5000, on a n × n board subject to t ...

  9. uva 11134 - Fabled Rooks(问题转换+优先队列)

    题目链接:uva 11134 - Fabled Rooks 题目大意:给出n,表示要在n*n的矩阵上放置n个车,并且保证第i辆车在第i个区间上,每个区间给出左上角和右小角的坐标.另要求任意两个车之间不 ...

随机推荐

  1. SSIS 数据流的执行树和数据管道

    数据流组件的设计愿景是快速处理海量的数据,为了实现该目标,SSIS数据源引擎需要创建执行树和数据管道这两个数据结构,而用户为了快速处理数据流,必须知道各个转换组件的阻塞性,充分利用流式处理流程,利用更 ...

  2. SpringBoot文件上传异常之提示The temporary upload location xxx is not valid

    原文: 一灰灰Blog之Spring系列教程文件上传异常原理分析 SpringBoot搭建的应用,一直工作得好好的,突然发现上传文件失败,提示org.springframework.web.multi ...

  3. 软件RAID

    软件RAID也必须在多磁盘系统中才能实现.实现RAID1最少要拥有两块硬盘,而实现RAID5则最少要拥有三块硬盘.通常情况下,操作系统所在磁盘采用RAID1,而数据所在磁盘采用RAID5.   卷的类 ...

  4. 第五章 if语句

    5.2条件测试 使用==判断相当: 使用!=判断不相等: 每条if语句的核心都是一个值为Tre或False的表达式,这种表达式被称为条件测试,如果条件测试的值为Ture,则执行紧跟在if语句后面的代码 ...

  5. python3 拼接字符串的7种方法

    1.直接通过(+)操作符拼接 1 2 >>> 'Hello' + ' ' + 'World' + '!' 'Hello World!' 使用这种方式进行字符串连接的操作效率低下,因为 ...

  6. 【RL系列】Multi-Armed Bandit问题笔记

    这是我学习Reinforcement Learning的一篇记录总结,参考了这本介绍RL比较经典的Reinforcement Learning: An Introduction (Drfit) .这本 ...

  7. 启动Nodejs服务

    vs code 中间创建 1.  settings.json { , { , { 'Content-Type': 'text/plain;charset=utf-8' })

  8. 方正 ignb路由器设置备份(自用笔记)

    192.168.15.96255.255.255.0192.168.15.1219.232.46.61219.141.136.10

  9. Python List Comprehension

    (一)使用List Comprehension的好处 在了解Python的List Comprehension之前,我们习惯使用for循环创建列表,比如下面的例子: numbers = range(1 ...

  10. bash登录过程 其实还不太了解,先码后看

    在刚登录Linux时,首先启动 /etc/profile 文件,然后再启动用户目录下的 ~/.bash_profile. ~/.bash_login或 ~/.profile文件中的其中一个,执行的顺序 ...