UVA12633(用于计数的FFT)

来源:互联网 发布:奥登nba健康数据 编辑:程序博客网 时间:2024/06/09 13:21

V-judge题面

题意就是有一个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[ik]

就是一个卷积了,上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;}