我们需要找到一个把所有同一对角线的方格放到一起的方法。把列反一下就可以把同一对角线的看成 x+y 相同的位置。把没有被覆盖的行和列卷积一下就得到了每个对角线上没有被行或者列覆盖的点的个数。把没有被覆盖的对角线累加上即可。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=300010;
const double pi=acos(-1);
struct Complex
{
double x,y;
Complex operator + (const Complex &c) const
{
return (Complex){x+c.x,y+c.y};
}
Complex operator - (const Complex &c) const
{
return (Complex){x-c.x,y-c.y};
}
Complex operator * (const Complex &c) const
{
return (Complex){x*c.x-y*c.y,x*c.y+y*c.x};
}
}a[maxn],b[maxn],w[maxn],t1,t2;
int visr[maxn],visc[maxn],vis[maxn],rev[maxn],
l,m,r,c,n;
void fft(Complex *a,int fl)
{
int x;
for (int i=0;i<l;i++)
if (rev[i]>i)
swap(a[i],a[rev[i]]);
for (int i=1;i<=m;i++)
for (int j=0;j<l;j+=(1<<i))
{
x=0;
for (int k=j;k<j+(1<<i-1);k++)
{
t1=a[k];
t2=a[k+(1<<i-1)];
a[k]=t1+w[x]*t2;
a[k+(1<<i-1)]=t1-w[x]*t2;
x+=fl*(1<<m-i);
if (x<0) x+=1<<m;
}
}
}
LL solve()
{
int x,y;
LL ans=0;
scanf("%d%d%d",&r,&c,&n);
memset(visr,0,sizeof(visr));
memset(visc,0,sizeof(visc));
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(rev,0,sizeof(rev));
for (int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
x--;
y=c-y;
vis[x+y]=visr[x]=visc[y]=1;
}
for (int i=0;i<r;i++) a[i]=(Complex){1-visr[i],0};
for (int i=0;i<c;i++) b[i]=(Complex){1-visc[i],0};
m=0;
while ((1<<m)<r+c-1) m++;
l=1<<m;
w[0]=(Complex){1,0};
w[1]=(Complex){cos(2*pi/l),sin(2*pi/l)};
for (int i=2;i<l;i++)
{
w[i]=w[i/2]*w[i/2];
if (i&1) w[i]=w[i]*w[1];
}
for (int i=0;i<l;i++)
for (int j=0;j<m;j++)
rev[i]|=((i>>j)&1)<<m-j-1;
fft(a,1);
fft(b,1);
for (int i=0;i<l;i++) a[i]=a[i]*b[i];
fft(a,-1);
for (int i=0;i<l;i++)
if (!vis[i])
ans+=int(a[i].x/l+0.5);
return ans;
}
int main()
{
//freopen("in","r",stdin);
int T;
scanf("%d",&T);
for (int K=1;K<=T;K++) printf("Case %d: %lld\n",K,solve());
}