题意:


给你一个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. 多栏布局与JS实现瀑布流

    css3属性之多栏布局与JS实现瀑布流 背景:之前打算自己总结一下flex布局的知识点,发现自己无从下手,原因在何处:我反思了一下,其实原因很简单,使用的次数少,更多的时间使用了百分比,浮动和定位解决 ...

  2. 关于AutoMapper和WCF的一些认识

    现在互联网时代呈尚快速开发,快速迭代.伴随着必然产生一些好用的第三方工具,今天有幸看到了Automapper这种类似ORM的框架,但是跟ORM还不太一样, ORM是实体和数据库表之间的映射,而此框架主 ...

  3. STM8S——watchdog(IWDG)

    IWDG工作原理: 1.当键值寄存器(IWDG_KR)中写入数值0xCC后,独立看门狗就会被启动,计数器开始从它的复位值0xFF开始递减计数,当计数减到0x00时就会产生一个复位信号. 2.使用IWD ...

  4. 开源项目CIIP(企业信息管理系统框架).2018.0904版更新介绍

    源码: https://github.com/tylike/CIIP https://gitee.com/ciip/CIIP 一,CIIP的目标是什么? 更加简单,快速的建立信息类管理系统.让实施人员 ...

  5. C# 代码备份数据库 ,不需要 其他 DLL

    protected void Button1_Click(object sender, EventArgs e)    {        ///        ///备份方法        ///  ...

  6. jQuery中turn.js(翻页效果)学习笔记

    Turn.js是一个内置的jQuery翻页插件1 html中引入<script type="text/javascript" src="js/turn.js&quo ...

  7. c++面向对象程序设计总结(类的使用)

    本篇算是学习c++有关类的知识的一些易错点吧..... 并不是特别详细,以后会更新吧.... 几点并不关于类的东西 1.函数模板,用虚拟类型来实现模板的功能 #include<iostream& ...

  8. Webrtc源码走读(一)

    阅读event_wrapper.h   event_wrapper_win.cpp 的实现 自己对“事件”这个词没有深的理解,通过看段代码,好像有点感觉,类似与C#的AutoResetEvent

  9. 【Coursera-ML-Notes】线性回归(上)

    什么是机器学习 关于机器学习,有以下两种不同的定义. 机器学习是研究如何使电脑具备学习能力,而不用显式编程告诉它该怎么做. the field of study that gives computer ...

  10. MySQL基础练习(二)

    第一个例子我们编写一个 SQL 查询,列出所有超过或等于5名学生的课. 先建表 CREATE TABLE courses( student ) NOT NULL, class ) NOT NULL ) ...