【FFT】UVa12633 Super Rooks on Chessboard

分析:

如果忽略斜向的情况,那么这道题就很简单了:
求出所有没被覆盖的行数,以及所有没被覆盖的列数,乘起来就是没被横向和纵向覆盖的格子总数。
现在考虑斜向的情况,如果没有被横向和纵向的干扰,那么每一条斜线覆盖的点数都是可计算的。但由于横向与纵向的存在,所以要加回来它们也覆盖的位置(因为被重复计数了)。

用一个多项式 A x 表示第x行是否被覆盖(被覆盖为0,未被覆盖为1)
用一个多项式 B y 表示第y列是否被覆盖(同上)

用x-y可以表示这个点所在的斜线编号,所以需要将B反序,
再求出B反序后的 A × B ,这里面每一项的系数即为那一条斜线中:没被横向与纵向覆盖的点的总数。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 200010
typedef long long ll;
const int G=3;
const int siz=131072;
using namespace std;
const double Pi=acos(-1);
struct cpx{
    double r,i;
    cpx() {}
    cpx(double _r,double _i):r(_r),i(_i) {}
    cpx operator * (const cpx &a) const{
        return cpx(r*a.r-i*a.i,r*a.i+i*a.r);
    }
    cpx operator + (const cpx &a) const{
        return cpx(r+a.r,i+a.i);
    }
    cpx operator - (const cpx &a) const{
        return cpx(r-a.r,i-a.i);
    }
};
void fft(cpx *a,int f,int N){
    int i,j,k;
    for(i=1,j=0;i<N;i++){
        for(int d=N;j^=d>>=1,~j&d;);
        if(i<j)
            swap(a[i],a[j]);
    }
    for(i=1;i<N;i<<=1){
        cpx wn(cos(Pi/i),f*sin(Pi/i));
        for(j=0;j<N;j+=i<<1){
            cpx w(1,0);
            for(k=0;k<i;k++,w=w*wn){
                cpx x=a[j+k],y=w*a[i+j+k];
                a[j+k]=x+y;
                a[i+j+k]=x-y;
            }
        }
    }
    if(f==-1)
        for(i=0;i<N;i++)
            a[i].r/=N;
}
cpx A[MAXN],B[MAXN];
int ts,r,c,m;
pair<int,int> a[MAXN];
bool usedx[MAXN],usedy[MAXN],used[MAXN];
int main(){
    SF("%d",&ts);
    for(int Cas=1;Cas<=ts;Cas++){
        memset(usedx,0,sizeof usedx);
        memset(usedy,0,sizeof usedy);
        memset(used,0,sizeof used);
        memset(A,0,sizeof A);
        memset(B,0,sizeof B);
        SF("%d%d%d",&r,&c,&m);  
        for(int i=1;i<=m;i++){
            SF("%d%d",&a[i].first,&a[i].second);
            usedx[a[i].first]=1;
            usedy[a[i].second]=1;
        }
        ll cntx=0,cnty=0;
        for(int i=1;i<=r;i++)
            if(usedx[i]==0)
                cntx++;
        for(int i=1;i<=c;i++)
            if(usedy[i]==0)
                cnty++;
        ll sum=cntx*cnty;
        for(int i=1;i<=r;i++)
            if(usedx[i]==0)
                A[i].r=1;
        for(int i=1;i<=c;i++)
            if(usedy[i]==0)
                B[50000-i].r=1;
        fft(A,1,siz);
        fft(B,1,siz);
        for(int i=0;i<=siz;i++)
            A[i]=A[i]*B[i];
        fft(A,-1,siz);
        for(int i=1;i<=m;i++){
            int xs=a[i].first-a[i].second+50000;
            if(used[xs]==0){
                sum-=(long long)(A[xs].r+0.5);
                used[xs]=1;
            }
        }
        PF("Case %d: %lld\n",Cas,sum);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/80783045