题意就是有一个R*C的矩阵,上面有一些点。每个点能控制所在行,所在列和所在主对角线(从左上到右下的一条对角线),问整个矩阵有多少个点没有被控制。
如果没有主对角线,则ANS=没被控制的行数*没被控制的列数。
根据主对角线的性质,一条主对角线上的点的横纵坐标的差为定值,设为k,那么就可以用k代表一条主对角线。
我们可以枚举每条被控制的主对角线k,要知道的便是k上有多少点没有被控制,设为f[k]。
再构造两个函数,a[i]为第i行是否被控制,若被控制则为0,否则为1。b[i]为第i列是否被控制,若被控制则为0,否则为1。就有
f[k]=∑i=max(0,k)Ra[i]∗b[i−k]
就是一个卷积了,上FFT就可以了。
学完牛顿迭代法,伯努利数…这些幂级数的东西,就可以摆脱FFT了去学搜索了。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=200200;
const LL p=1004535809,g=3;
int n,rev[N];
LL cheng(LL a,LL b)
{
LL res=1ll;
for(;b;b>>=1,a=a*a%p)
if(b&1)
res=res*a%p;
return res;
}
void init(int lim)
{
n=1;
int k=-1;
while(n<=lim)
n<<=1,k++;
for(int i=0;i<n;i++)
rev[i]=(rev[i>>1]>>1) | ((i&1)<<k);
}
void ntt(LL *a,int ops)
{
for(int i=0;i<n;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int l=2;l<=n;l<<=1)
{
int m=l>>1;
LL wn;
if(ops)
wn=cheng(g,(p-1)/l);
else
wn=cheng(g,p-1-(p-1)/l);
for(int i=0;i<n;i+=l)
{
LL w=1ll;
for(int k=0;k<m;k++)
{
LL t=a[i+k+m]*w%p;
a[i+k+m]=(a[i+k]-t+p)%p;
a[i+k]=(a[i+k]+t)%p;
w=w*wn%p;
}
}
}
if(!ops)
{
LL Inv=cheng(n,p-2);
for(int i=0;i<n;i++)
a[i]=a[i]*Inv%p;
}
}
LL ans;
int T,mx,R,C,nn;
LL aa[N],bb[N],cc[N];
int hang,lie;
bool dj[N];
int main()
{
cin>>T;
for(int ii=1;ii<=T;ii++)
{
cin>>R>>C>>nn;
hang=R;
lie=C;
mx=max(R,C);
R--;
C--;
init(R+C+5);
for(int i=0;i<n;i++)
aa[i]=bb[i]=cc[i]=0;
mmst(dj,0);
for(int i=0;i<=R;i++)
aa[i]=1;
for(int i=0;i<=C;i++)
bb[i]=1;
for(int i=1;i<=nn;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x--;
y--;
dj[x-y+mx]=1;
if(aa[x])
hang--;
if(bb[y])
lie--;
aa[x]=0;
bb[y]=0;
}
for(int i=0;i<=C;i++)
cc[i]=bb[C-i];
ntt(aa,1);
ntt(cc,1);
for(int i=0;i<n;i++)
aa[i]=aa[i]*cc[i]%p;
ntt(aa,0);
ans=(LL)hang*lie;
for(int i=0;i<n;i++)
if(dj[i-C+mx])
ans-=aa[i];
cout<<"Case "<<ii<<": "<<ans<<endl;
}
return 0;
}