题意:


给你一个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. 用Angule Cli创建Angular项目

    Angular4.0来了,更小,更快,改动少 接下来为Angular4.0准备环境和学会使用Angular cli项目 1.环境准备: 1)在开始工作之前我们必须设置好开发环境 如果你的机器上还没有安 ...

  2. C#,清晨随手写

    关于昨晚“猜拳”的博客   大家一定要记得,C#的书写规范是很严格的   很严格很严格很严格  简单的说  下面这样就没办法取值 但是这样就可以取值 插眼,开撸

  3. SpringBoot日记——Thymeleaf模板引擎篇

    开发通常我们都会使用模板引擎,比如:JSP.Velocity.Freemarker.Thymeleaf等等很多,那么模板引擎是干嘛用的? 模板引擎,顾名思义,是一款模板,模板中可以动态的写入一些参数, ...

  4. Scrapy中的POST请求发送和递归爬取

    POST请求发送 重写爬虫应用文件中继承Spider类的 类的里面的start_requests(self)这个方法 def start_requests(self): #请求的url post_ur ...

  5. Oracle中Date和Timestamp的区别

    Date和Timestamp精度不一样: 01)Timestamp精确到了秒的小数点(如:2018-11-13 16:40:03.698): 02)Date只精确到整数的秒(如:2018-11-13 ...

  6. Spring集成Kafka-注解,xml配置2种方式实现

    准备工作: 1.安装kafka+zookeeper环境 2.利用命令创建好topic 参考官网 http://kafka.apache.org/documentation/ 一XML配置文件方式实现

  7. kali虚拟机安装后操作[配置ssh,安装vmtools,更新源]

    更新源 # 打开控制台, 输入以下命令打开编辑器修改配置文件 $ leafpad /etc/apt/sources.list #kali官方源 deb http://http.kali.org/kal ...

  8. java基础---类加载和对象创建过程

    类中可以存在的成员: class A{ 静态成员变量: 非静态成员变量: 静态函数: 非静态函数: 构造函数 A(..){...} 静态代码块 static{...} 构造代码块 {...} } 类加 ...

  9. java多线程相关代码

    1.创建线程的三种方式 使用Thread package com.wpbxx.test; //1.自定义一个类,继承java.lang包下的Thread类 class MyThread extends ...

  10. vue 组件-父组件传值给子组件

    父组件通过属性,传值给子组件,子组件通过,props数组里的名称来接受父组件传过来的值. HTML部分: <div id="app"> <tmp1 :parent ...