题目传送门:https://cn.vjudge.net/problem/UVA-12633
题目大意:现在有一个r*c的白色棋盘,上面有n个棋子。每个棋子会将它所在行和所在列,以及所在主对角线染黑(主对角线就是左上到右下)。问最终有多少个白色格子。不超过20组数据,r,c,n<=50000。
题目分析:做了几道CF的题愉悦身心之后,我又开始刷回FFT的题了(虽然这题是水题)。
如果每个棋子只染所在行和列,那么这就是个简单的计数问题。现在我们需要知道每个棋子所在的主对角线还有多少没有染成黑色。由于同一条主对角线上的格子,横纵坐标之差为定值,不妨将没染的行,列设为1,将列翻转,然后做FFT即可。
难得的FFT20分钟1A。
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=200000;
const double pi=acos(-1.0);
typedef long long LL;
struct Complex
{
double X,Y;
Complex (double a=0.0,double b=0.0) : X(a),Y(b) {}
} ;
Complex operator+(Complex a,Complex b){return Complex(a.X+b.X,a.Y+b.Y);}
Complex operator-(Complex a,Complex b){return Complex(a.X-b.X,a.Y-b.Y);}
Complex operator*(Complex a,Complex b){return Complex(a.X*b.X-a.Y*b.Y,a.X*b.Y+a.Y*b.X);}
int Rev[maxn];
Complex A[maxn];
Complex B[maxn];
bool fx[maxn];
bool fy[maxn];
int numx,numy;
int px[maxn];
int py[maxn];
int t,n,r,c;
LL ans;
int N,Lg;
void DFT(Complex *a,double f)
{
for (int i=0; i<N; i++)
if (i<Rev[i]) swap(a[i],a[ Rev[i] ]);
for (int len=2; len<=N; len<<=1)
{
int mid=len>>1;
double ang=2.0*pi/((double)len);
Complex e( cos(ang) , f*sin(ang) );
for (Complex *p=a; p!=a+N; p+=len)
{
Complex wn(1.0,0.0);
for (int i=0; i<mid; i++)
{
Complex temp=wn*p[mid+i];
p[mid+i]=p[i]-temp;
p[i]=p[i]+temp;
wn=wn*e;
}
}
}
}
void FFT()
{
for (int i=0; i<N; i++)
{
Rev[i]=0;
for (int j=0; j<Lg; j++)
if ( i&(1<<j) ) Rev[i]|=( 1<<(Lg-j-1) );
}
DFT(A,1.0);
DFT(B,1.0);
for (int i=0; i<N; i++) A[i]=A[i]*B[i];
DFT(A,-1.0);
for (int i=0; i<N; i++) A[i].X/=((double)N);
}
int main()
{
freopen("12633.in","r",stdin);
freopen("12633.out","w",stdout);
scanf("%d",&t);
for (int g=1; g<=t; g++)
{
scanf("%d%d%d",&r,&c,&n);
for (int i=1; i<=r; i++) fx[i]=false;
for (int i=1; i<=c; i++) fy[i]=false;
for (int i=1; i<=n; i++)
{
scanf("%d%d",&px[i],&py[i]);
fx[ px[i] ]=true;
fy[ py[i] ]=true;
}
numx=numy=0;
for (int i=1; i<=r; i++) if (fx[i]) numx++;
for (int i=1; i<=c; i++) if (fy[i]) numy++;
ans=0;
ans-=( (long long)numx*(long long)c+(long long)numy*(long long)r );
ans+=( (long long)r*(long long)c+(long long)numx*(long long)numy );
for (int i=0; i<r; i++)
if (fx[i+1]) A[i]=Complex(0.0,0.0);
else A[i]=Complex(1.0,0.0);
for (int i=0; i<c; i++)
if (fy[i+1]) B[i]=Complex(0.0,0.0);
else B[i]=Complex(1.0,0.0);
for (int i=0; i<c-i-1; i++) swap(B[i],B[c-i-1]);
N=1,Lg=0;
while (N<r+c) N<<=1,Lg++;
for (int i=r; i<N; i++) A[i]=Complex(0.0,0.0);
for (int i=c; i<N; i++) B[i]=Complex(0.0,0.0);
FFT();
for (int i=1; i<=n; i++)
{
int x=px[i]-1,y=py[i]-1;
y=c-y-1;
ans-=( (int)floor(A[x+y].X+0.5) );
A[x+y].X=0.0;
}
printf("Case %d: %lld\n",g,ans);
}
return 0;
}