Super Rooks on Chessboard,UVA - 12633
https://vjudge.net/problem/UVA-12633/origin
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.
思路: 首先很容易求出只覆盖横竖时总共覆盖的格子数,然后进行斜线覆盖数的计算,如果一个格子的坐标为(a,b),那么它覆盖的斜线方程为x +y = a+b(将左下角看作(0,0)),即会将这条斜线上的所有格子覆盖,首先加上这条斜线上的格子数,然后因为横竖已经覆盖了一些格子,需要先分别减去这条斜线上横竖覆盖了的格子数,然后还存在一种情况就是横竖覆盖了这条斜线上的同一个格子,就多减了一次,需要再加上,即需要知道有多少横竖的x +y = a+b,可以一开始记录下哪些横被覆盖,哪些竖被覆盖,然后做下卷积,a+b的系数即为对应结果
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ri register int
#define MAXN 50005
#define ll long long
using namespace std;
const double pi=acos(-1.0);
struct cpx
{
double r, i;
inline void operator +=(const cpx &b){ r+=b.r, i+=b.i;}
inline cpx operator +(const cpx &b)const{ return (cpx){r+b.r, i+b.i};}
inline cpx operator -(const cpx &b)const{ return (cpx){r-b.r, i-b.i};}
inline cpx operator *(const cpx &b)const{ return (cpx){r*b.r-i*b.i, r*b.i+i*b.r};}
inline cpx operator *(const double b)const{ return (cpx){r*b, i*b};}
inline cpx operator ~()const{return (cpx){r, -i};}
}a[MAXN<<2],b[MAXN << 2],w[MAXN<<2];
inline void DFT_(cpx *f, int n)
{
for(ri i=0, j=0; i<n; ++i)
{
if(i>j) swap(f[i], f[j]);
for(ri k=n>>1; (j^=k)<k; k>>=1);
}
for(ri i=1; i<n; i<<=1) for(ri j=0; j<n; j+=i<<1)
for(ri k=j; k<j+i; ++k)
{
cpx t=w[i+k-j]*f[k+i];
f[k+i]=f[k]-t, f[k]+=t;
}
}
inline void DFT(cpx *f, int n)
{
if(n==1) return;
n>>=1;
static cpx a[MAXN<<1];
for(ri i=0; i<n; ++i) a[i]=(cpx){f[i<<1].r, f[i<<1|1].r};
DFT_(a, n);
for(ri i=0; i<n; ++i)
{
cpx q=~a[(n-i)&(n-1)], x=(a[i]+q)*0.5, y=(a[i]-q)*(cpx){0, -0.5}, t=y*w[n+i];
f[i]=x+t, f[n+i]=x-t;
}
}
inline void IDFT(cpx *f, int n)
{
if(n==1) return;
reverse(f+1, f+n), n>>=1;
static cpx a[MAXN<<1];
for(ri i=0; i<n; ++i)
a[i]=(f[i]+f[i+n])*0.5 + (f[i]-f[i+n])*(cpx){0, 0.5}*w[n+i];
DFT_(a, n);
double k=1.0/n;
for(ri i=0; i<n; ++i) f[i<<1]=(cpx){a[i].r*k, 0}, f[i<<1|1]=(cpx){a[i].i*k, 0};
}
int n,m,k;
int visr[MAXN],visc[MAXN],visd[MAXN<<1];
int main()
{
int t;
scanf("%d",&t);
for(int cas = 1;cas <= t;++cas)
{
scanf("%d%d%d",&n,&m,&k);
int x,y;
memset(visr,0,sizeof(visr));
memset(visc,0,sizeof(visc));
memset(visd,0,sizeof(visd));
while(k--)
{
scanf("%d%d",&x,&y);
visr[n+1-x] = visc[y] = visd[n+1-x+y] = 1;
}
n,m;
int len = 1;
while(len < n+m+2) len<<=1;
for(int i = 0;i <= n;i++)
a[i] = (cpx){(double)visr[i],0};
for(int i = n+1;i < len;i++)
a[i] = (cpx){0,0};
for(int i = 0;i <= m;i++)
b[i] = (cpx){(double)visc[i],0};
for(int i = m+1;i < len;i++)
b[i] = (cpx){0,0};
for(ri i=1; i<len; i<<=1)
{
w[i]=(cpx){1, 0};
for(ri j=1; j<i; ++j)
w[i+j]=((j&31)==1?(cpx){cos(pi*j/i), sin(pi*j/i)}:w[i+j-1]*w[i+1]);
}
DFT(a,len),DFT(b,len);
for(int i = 0;i < len;++i)
a[i] = a[i] * b[i];
IDFT(a,len);
ll ans = 0,sumr = 0;
for(int i = 1;i <= n;++i)
if(visr[i])
++sumr;
ans = sumr * m;
for(int i = 1;i <= m;++i)
if(visc[i])
ans += n-sumr;
for(int i = 2;i <= n;++i)
visr[i] = visr[i-1] + visr[i];
for(int i = 2;i <= m;++i)
visc[i] = visc[i-1] + visc[i];
for(int i = 2;i <= n+m;++i)
{
if(visd[i])
{
int x1,y1,x2,y2;
if(i-1 <= n)
x2 = i-1,y1 = 1;
else
x2 = n,y1 = i-n;
if(i-1 <= m)
y2 = i-1,x1 = 1;
else
y2 = m,x1 = i-m;
ans += max(x2-x1+1,y2-y1+1) - visr[x2] + visr[x1-1] - visc[y2] + visc[y1-1] + (ll)(a[i].r+0.5);
}
}
printf("Case %d: %lld\n",cas,1ll*n*m-ans);
}
return 0;
}
/*
//
1
4 5 4
2 3
4 3
3 4
2 5
*/