题解:
第一眼满眼骚操作,然后全部否掉。
然后屈服于题解,才发现这题这么执掌。
首先,如果这个东西是普通的车,那我们可以记录一下$x,y$的覆盖情况,然后减一下;
但是这个可以斜着走。
所以我们可以转一下$x/y$,记录哪一行哪一列没有被覆盖,然后求一下卷积。
得到的是每一条对角线上没有被覆盖的格子数。
如果这条对角线上有子就不统计到答案里。
就这么简单……
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 160050 #define ll long long const double Pi = acos(-1.0); template<typename T> inline void read(T&x) { T f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } struct cp { double x,y; cp(){} cp(double x,double y):x(x),y(y){} cp operator + (const cp&a)const{return cp(x+a.x,y+a.y);} cp operator - (const cp&a)const{return cp(x-a.x,y-a.y);} cp operator * (const cp&a)const{return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }; int to[2*N]; void fft(cp *a,int len,int k) { for(int i=0;i<len;i++) if(i<to[i])swap(a[i],a[to[i]]); for(int i=1;i<len;i<<=1) { cp w0(cos(Pi/i),k*sin(Pi/i)); for(int j=0;j<len;j+=(i<<1)) { cp w(1,0); for(int o=0;o<i;o++,w=w*w0) { cp w1 = a[j+o],w2 = a[j+o+i]*w; a[j+o] = w1+w2; a[j+o+i] = w1-w2; } } } } int T,n,m,k,lim=1,l; bool vis[2*N],vx[N],vy[N]; cp a[2*N],b[2*N],c[2*N]; ll ans; int main() { read(T); for(int cse=1;cse<=T;cse++) { memset(vis,0,sizeof(vis)); memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); read(n),read(m),read(k); for(int x,y,i=1;i<=k;i++) { read(x),read(y); x=n-x,y--; vis[x+y]=1; vx[x]=vy[y]=1; } n--,m--; lim=1,l=0; while(lim<2*(n+m))lim<<=1,l++; for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1))); for(int i=0;i<=n;i++)a[i].x=(!vx[i]); for(int i=0;i<=m;i++)b[i].x=(!vy[i]); fft(a,lim,1),fft(b,lim,1); for(int i=0;i<lim;i++)c[i]=a[i]*b[i]; fft(c,lim,-1); ans = 0; for(int i=0;i<=n+m;i++) if(!vis[i]) ans+=(ll)(c[i].x/lim+0.5); printf("Case %d: %lld ",cse,ans); } return 0; }